Currently deployed, has vesting tracker

This commit is contained in:
2025-07-15 23:42:01 +02:00
parent c8da95a2b0
commit 945b69deda
6 changed files with 1664 additions and 63 deletions

View File

@@ -36,7 +36,7 @@ error StakeNotInSellState();
// File: paca.sol // File: paca.sol
contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUpgradeable { contract PacaFinanceWithBoostAndScheduleBase is Initializable, ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
@@ -136,8 +136,6 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
uint256 public unlockDelay; uint256 public unlockDelay;
uint256 public withdrawLiabilities; uint256 public withdrawLiabilities;
mapping(address => WithdrawStake[]) public withdrawStake; mapping(address => WithdrawStake[]) public withdrawStake;
mapping(address => WithdrawVesting[]) public withdrawVesting;
uint256 private withdrawVestingCounter;
uint256 public restakeBonus; uint256 public restakeBonus;
mapping(address => uint256) public addressFixedRate; mapping(address => uint256) public addressFixedRate;
mapping(address => mapping(uint256 => SellStake)) public sellStakes; mapping(address => mapping(uint256 => SellStake)) public sellStakes;
@@ -147,6 +145,12 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
mapping(address => mapping(uint256 => uint256)) private sellStakeKeyIndex; mapping(address => mapping(uint256 => uint256)) private sellStakeKeyIndex;
uint256 public sellMin; uint256 public sellMin;
mapping(address => WithdrawVesting[]) private withdrawVestingActual;
uint256 private withdrawVestingCounterActual;
// Track total withdraw vesting liabilities by token address
mapping(address => uint256) public withdrawVestingLiabilities;
// Events // Events
event Staked(address indexed user, uint256 amount); event Staked(address indexed user, uint256 amount);
event RewardClaimed(address indexed user, uint256 reward); event RewardClaimed(address indexed user, uint256 reward);
@@ -451,14 +455,14 @@ contract PacaFinanceWithBoostAndScheduleUSDC is Initializable, ReentrancyGuardUp
dollarsVested[oldAddress] = 0; dollarsVested[oldAddress] = 0;
// Migrate pending vesting withdrawals // Migrate pending vesting withdrawals
WithdrawVesting[] storage oldWithdrawVestings = withdrawVesting[oldAddress]; WithdrawVesting[] storage oldWithdrawVestings = withdrawVestingActual[oldAddress];
uint256 withdrawVestingCount = oldWithdrawVestings.length; uint256 withdrawVestingCount = oldWithdrawVestings.length;
if (withdrawVestingCount > 0) { if (withdrawVestingCount > 0) {
WithdrawVesting[] storage newWithdrawVestings = withdrawVesting[newAddress]; WithdrawVesting[] storage newWithdrawVestings = withdrawVestingActual[newAddress];
for (uint256 i = 0; i < withdrawVestingCount; i++) { for (uint256 i = 0; i < withdrawVestingCount; i++) {
newWithdrawVestings.push(oldWithdrawVestings[i]); newWithdrawVestings.push(oldWithdrawVestings[i]);
} }
delete withdrawVesting[oldAddress]; delete withdrawVestingActual[oldAddress];
} }
} }
@@ -824,7 +828,7 @@ function withdraw(uint256 _stakeIndex) external nonReentrant {
* @param _vestingId The vesting ID to withdraw * @param _vestingId The vesting ID to withdraw
*/ */
function withdrawVestingToken(uint256 _vestingId) external nonReentrant { function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
WithdrawVesting[] storage userVestings = withdrawVesting[msg.sender]; WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender];
if (userVestings.length == 0) revert NoStakesAvailable(); if (userVestings.length == 0) revert NoStakesAvailable();
for (uint256 i = 0; i < userVestings.length; ++i) { for (uint256 i = 0; i < userVestings.length; ++i) {
@@ -842,6 +846,9 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
// Update state before external calls // Update state before external calls
vestingWithdraw.amount = 0; vestingWithdraw.amount = 0;
// Decrement withdraw vesting liabilities for this token
withdrawVestingLiabilities[_token] -= _amount;
// Transfer tokens // Transfer tokens
IERC20(_token).safeTransfer(msg.sender, _amount); IERC20(_token).safeTransfer(msg.sender, _amount);
emit StakeWithdrawn(msg.sender, _amount, _vestingId); emit StakeWithdrawn(msg.sender, _amount, _vestingId);
@@ -849,7 +856,6 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
} }
} }
// Revert if no matching vesting with non-zero amount was found
revert StakeNotFound(); revert StakeNotFound();
} }
@@ -1009,13 +1015,16 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
vestedTotal[vesting.token] -= amountToClaim; vestedTotal[vesting.token] -= amountToClaim;
// Add vesting claims to cooldown queue // Add vesting claims to cooldown queue
withdrawVesting[msg.sender].push(WithdrawVesting({ withdrawVestingActual[msg.sender].push(WithdrawVesting({
vestingId: withdrawVestingCounter++, vestingId: withdrawVestingCounterActual++,
amount: amountToClaim, amount: amountToClaim,
unlockTime: block.timestamp + unlockDelay, unlockTime: block.timestamp + unlockDelay,
token: vesting.token token: vesting.token
})); }));
// Increment withdraw vesting liabilities for this token
withdrawVestingLiabilities[vesting.token] += amountToClaim;
emit VestingClaimed(msg.sender, amountToClaim, 0); emit VestingClaimed(msg.sender, amountToClaim, 0);
} }
@@ -1062,13 +1071,16 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
vestedTotal[_token] -= totalReward; vestedTotal[_token] -= totalReward;
// Add vesting claims to cooldown queue // Add vesting claims to cooldown queue
withdrawVesting[msg.sender].push(WithdrawVesting({ withdrawVestingActual[msg.sender].push(WithdrawVesting({
vestingId: withdrawVestingCounter++, vestingId: withdrawVestingCounterActual++,
amount: totalReward, amount: totalReward,
unlockTime: block.timestamp + unlockDelay, unlockTime: block.timestamp + unlockDelay,
token: _token token: _token
})); }));
// Increment withdraw vesting liabilities for this token
withdrawVestingLiabilities[_token] += totalReward;
emit RewardClaimed(msg.sender, totalReward); emit RewardClaimed(msg.sender, totalReward);
} }
@@ -1237,15 +1249,23 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
/// @param user The address to evaluate. /// @param user The address to evaluate.
/// @return An array of WithdrawVesting for the given user. /// @return An array of WithdrawVesting for the given user.
function getAllWithdrawVestings(address user) external view returns (WithdrawVesting[] memory) { function getAllWithdrawVestings(address user) external view returns (WithdrawVesting[] memory) {
return withdrawVesting[user]; return withdrawVestingActual[user];
} }
/// @notice Returns the current withdraw vesting counter value /// @notice Returns the current withdraw vesting counter value
/// @return Current counter value for tracking unique withdrawal IDs /// @return Current counter value for tracking unique withdrawal IDs
function getWithdrawVestingCounter() external view returns (uint256) { function getWithdrawVestingCounter() external view returns (uint256) {
return withdrawVestingCounter; return withdrawVestingCounterActual;
} }
/// @notice Test function for upgrade verification
/// @return Returns a constant value to verify upgrade worked
function testUpgradeFunction() external pure returns (uint256) {
return 888;
}
/// @notice Function to put a stake for sale. /// @notice Function to put a stake for sale.
/// Sets the original stake amount to 0 to prevent any alterations while for sale. /// Sets the original stake amount to 0 to prevent any alterations while for sale.
/// @param _stakeId The stake to sell. /// @param _stakeId The stake to sell.

View File

@@ -36,7 +36,7 @@ error StakeNotInSellState();
// File: paca.sol // File: paca.sol
contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUpgradeable { contract PacaFinanceWithBoostAndScheduleBsc is Initializable, ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
@@ -136,8 +136,6 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
uint256 public unlockDelay; uint256 public unlockDelay;
uint256 public withdrawLiabilities; uint256 public withdrawLiabilities;
mapping(address => WithdrawStake[]) public withdrawStake; mapping(address => WithdrawStake[]) public withdrawStake;
mapping(address => WithdrawVesting[]) public withdrawVesting;
uint256 private withdrawVestingCounter;
uint256 public restakeBonus; uint256 public restakeBonus;
mapping(address => uint256) public addressFixedRate; mapping(address => uint256) public addressFixedRate;
mapping(address => mapping(uint256 => SellStake)) public sellStakes; mapping(address => mapping(uint256 => SellStake)) public sellStakes;
@@ -147,6 +145,12 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
mapping(address => mapping(uint256 => uint256)) private sellStakeKeyIndex; mapping(address => mapping(uint256 => uint256)) private sellStakeKeyIndex;
uint256 public sellMin; uint256 public sellMin;
mapping(address => WithdrawVesting[]) private withdrawVestingActual;
uint256 private withdrawVestingCounterActual;
// Track total withdraw vesting liabilities by token address
mapping(address => uint256) public withdrawVestingLiabilities;
// Events // Events
event Staked(address indexed user, uint256 amount); event Staked(address indexed user, uint256 amount);
event RewardClaimed(address indexed user, uint256 reward); event RewardClaimed(address indexed user, uint256 reward);
@@ -207,6 +211,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
owners[_owner] = false; owners[_owner] = false;
} }
/// @notice Function to add a bot to the list (only callable by the contract owner) /// @notice Function to add a bot to the list (only callable by the contract owner)
function addBot(address bot) external onlyOwner { function addBot(address bot) external onlyOwner {
if (bot == address(0)) revert InvalidAddress(); if (bot == address(0)) revert InvalidAddress();
@@ -226,6 +231,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
emit PoolUpdated(_lockupPeriod, _dailyRewardRate); emit PoolUpdated(_lockupPeriod, _dailyRewardRate);
} }
function depositRewards(uint256 _amount) external onlyOwner { function depositRewards(uint256 _amount) external onlyOwner {
IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount);
pool.totalRewards = pool.totalRewards + _amount; pool.totalRewards = pool.totalRewards + _amount;
@@ -449,14 +455,14 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
dollarsVested[oldAddress] = 0; dollarsVested[oldAddress] = 0;
// Migrate pending vesting withdrawals // Migrate pending vesting withdrawals
WithdrawVesting[] storage oldWithdrawVestings = withdrawVesting[oldAddress]; WithdrawVesting[] storage oldWithdrawVestings = withdrawVestingActual[oldAddress];
uint256 withdrawVestingCount = oldWithdrawVestings.length; uint256 withdrawVestingCount = oldWithdrawVestings.length;
if (withdrawVestingCount > 0) { if (withdrawVestingCount > 0) {
WithdrawVesting[] storage newWithdrawVestings = withdrawVesting[newAddress]; WithdrawVesting[] storage newWithdrawVestings = withdrawVestingActual[newAddress];
for (uint256 i = 0; i < withdrawVestingCount; i++) { for (uint256 i = 0; i < withdrawVestingCount; i++) {
newWithdrawVestings.push(oldWithdrawVestings[i]); newWithdrawVestings.push(oldWithdrawVestings[i]);
} }
delete withdrawVesting[oldAddress]; delete withdrawVestingActual[oldAddress];
} }
} }
@@ -812,7 +818,7 @@ contract PacaFinanceWithBoostAndScheduleUSDT is Initializable, ReentrancyGuardUp
* @param _vestingId The vesting ID to withdraw * @param _vestingId The vesting ID to withdraw
*/ */
function withdrawVestingToken(uint256 _vestingId) external nonReentrant { function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
WithdrawVesting[] storage userVestings = withdrawVesting[msg.sender]; WithdrawVesting[] storage userVestings = withdrawVestingActual[msg.sender];
if (userVestings.length == 0) revert NoStakesAvailable(); if (userVestings.length == 0) revert NoStakesAvailable();
for (uint256 i = 0; i < userVestings.length; ++i) { for (uint256 i = 0; i < userVestings.length; ++i) {
@@ -830,6 +836,9 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
// Update state before external calls // Update state before external calls
vestingWithdraw.amount = 0; vestingWithdraw.amount = 0;
// Decrement withdraw vesting liabilities for this token
withdrawVestingLiabilities[_token] -= _amount;
// Transfer tokens // Transfer tokens
IERC20(_token).safeTransfer(msg.sender, _amount); IERC20(_token).safeTransfer(msg.sender, _amount);
emit StakeWithdrawn(msg.sender, _amount, _vestingId); emit StakeWithdrawn(msg.sender, _amount, _vestingId);
@@ -837,7 +846,6 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
} }
} }
// Revert if no matching vesting with non-zero amount was found
revert StakeNotFound(); revert StakeNotFound();
} }
@@ -997,13 +1005,16 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
vestedTotal[vesting.token] -= amountToClaim; vestedTotal[vesting.token] -= amountToClaim;
// Add vesting claims to cooldown queue // Add vesting claims to cooldown queue
withdrawVesting[msg.sender].push(WithdrawVesting({ withdrawVestingActual[msg.sender].push(WithdrawVesting({
vestingId: withdrawVestingCounter++, vestingId: withdrawVestingCounterActual++,
amount: amountToClaim, amount: amountToClaim,
unlockTime: block.timestamp + unlockDelay, unlockTime: block.timestamp + unlockDelay,
token: vesting.token token: vesting.token
})); }));
// Increment withdraw vesting liabilities for this token
withdrawVestingLiabilities[vesting.token] += amountToClaim;
emit VestingClaimed(msg.sender, amountToClaim, 0); emit VestingClaimed(msg.sender, amountToClaim, 0);
} }
@@ -1050,13 +1061,16 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
vestedTotal[_token] -= totalReward; vestedTotal[_token] -= totalReward;
// Add vesting claims to cooldown queue // Add vesting claims to cooldown queue
withdrawVesting[msg.sender].push(WithdrawVesting({ withdrawVestingActual[msg.sender].push(WithdrawVesting({
vestingId: withdrawVestingCounter++, vestingId: withdrawVestingCounterActual++,
amount: totalReward, amount: totalReward,
unlockTime: block.timestamp + unlockDelay, unlockTime: block.timestamp + unlockDelay,
token: _token token: _token
})); }));
// Increment withdraw vesting liabilities for this token
withdrawVestingLiabilities[_token] += totalReward;
emit RewardClaimed(msg.sender, totalReward); emit RewardClaimed(msg.sender, totalReward);
} }
@@ -1225,15 +1239,22 @@ function withdrawVestingToken(uint256 _vestingId) external nonReentrant {
/// @param user The address to evaluate. /// @param user The address to evaluate.
/// @return An array of WithdrawVesting for the given user. /// @return An array of WithdrawVesting for the given user.
function getAllWithdrawVestings(address user) external view returns (WithdrawVesting[] memory) { function getAllWithdrawVestings(address user) external view returns (WithdrawVesting[] memory) {
return withdrawVesting[user]; return withdrawVestingActual[user];
} }
/// @notice Returns the current withdraw vesting counter value /// @notice Returns the current withdraw vesting counter value
/// @return Current counter value for tracking unique withdrawal IDs /// @return Current counter value for tracking unique withdrawal IDs
function getWithdrawVestingCounter() external view returns (uint256) { function getWithdrawVestingCounter() external view returns (uint256) {
return withdrawVestingCounter; return withdrawVestingCounterActual;
} }
/// @notice Test function for upgrade verification
/// @return Returns a constant value to verify upgrade worked
function testUpgradeFunction() external pure returns (uint256) {
return 777;
}
/// @notice Function to put a stake for sale. /// @notice Function to put a stake for sale.
/// Sets the original stake amount to 0 to prevent any alterations while for sale. /// Sets the original stake amount to 0 to prevent any alterations while for sale.
/// @param _stakeId The stake to sell. /// @param _stakeId The stake to sell.

1435
contracts/sonic_paca.sol Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,8 @@
require("@openzeppelin/hardhat-upgrades"); require("@openzeppelin/hardhat-upgrades");
require("@nomicfoundation/hardhat-ignition-ethers"); require("@nomicfoundation/hardhat-ignition-ethers");
// require("@nomiclabs/hardhat-ethers");
// require("@nomiclabs/hardhat-etherscan");
require("hardhat-contract-sizer"); require("hardhat-contract-sizer");
// require("dotenv").config();
// require("hardhat-gas-reporter");
require("@nomicfoundation/hardhat-verify"); require("@nomicfoundation/hardhat-verify");
require("dotenv").config();
const env = process.env; const env = process.env;
// This is a sample Hardhat task. To learn how to create your own go to // This is a sample Hardhat task. To learn how to create your own go to
@@ -82,15 +79,8 @@ module.exports = {
networks: { networks: {
hardhat: { hardhat: {
forking: { forking: {
// MAINNET FORK url: `https://rpc.soniclabs.com`,
url: `https://bsc-mainnet.nodereal.io/v1/f82aa3b8072a46ccadf3024a96f0cff4`, blockNumber: 37000000,
// blockNumber: 30488174,
chainId: 56,
// TESTNET FORK
// url: `https://bsc-testnet.nodereal.io/v1/f82aa3b8072a46ccadf3024a96f0cff4`,
// blockNumber: 31828689,
// chainId: 97,
}, },
}, },
local: { local: {
@@ -132,26 +122,32 @@ module.exports = {
// gas: 2e9, // gas: 2e9,
}, },
mainnet: { mainnet: {
url: `https://bsc-dataseed1.binance.org`, url: env.MAINNET_RPC_URL || `https://bsc-dataseed1.binance.org`,
chainId: 56, chainId: 56,
accounts: env.PRIVATE_KEY ? [env.PRIVATE_KEY] : [],
}, },
base: { base: {
url: `https://base-mainnet.public.blastapi.io`, url: env.BASE_RPC_URL || `https://base-mainnet.public.blastapi.io`,
chainId: 8453, chainId: 8453,
accounts: env.PRIVATE_KEY ? [env.PRIVATE_KEY] : [],
}, },
sonic: { sonic: {
url: `https://rpc.soniclabs.com`, url: env.SONIC_RPC_URL || `https://rpc.soniclabs.com`,
chainId: 146, chainId: 146,
accounts: env.PRIVATE_KEY ? [env.PRIVATE_KEY] : [],
},
sonicfork: {
url: "http://127.0.0.1:8545",
forking: {
url: `https://rpc.soniclabs.com`,
blockNumber: 37513000, // Recent block
},
accounts: env.PRIVATE_KEY ? [env.PRIVATE_KEY] : [],
}, },
}, },
etherscan: { etherscan: {
enable: true, enable: true,
apiKey: { apiKey: "JRKR5T93RQTKVERUJ2NVE4T994TD66QGFH",
bbsc: "verifyContract",
base: "GN555QYEWPDFZ47H1TR5ASK693D38A69GY",
mainnet: "1I15826QJ4HHY2UTGK3EZEA4TNBT68FB83",
sonic: "N6DMIQQNJ7634I1ETH527Z1WZQM2Q6GEW8"
},
customChains: [ customChains: [
{ {
network: "bbsc", network: "bbsc",

View File

@@ -1,17 +1,24 @@
const { ethers, upgrades, run } = require("hardhat"); const { ethers, upgrades, run } = require("hardhat");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
require('dotenv').config(); require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const deploymentFile = path.join(__dirname, "deployedAddresses.json"); const deploymentFile = path.join(__dirname, "deployedAddresses.json");
async function main() { async function main() {
const privateKey = process.env.pk; const privateKey = process.env.PRIVATE_KEY;
const network = await hre.network.name; const network = await hre.network.name;
const wallet = new ethers.Wallet(privateKey, ethers.provider); let deployer;
const deployer = wallet.connect(ethers.provider); if (network === "hardhat" || network === "localhost") {
console.log(`Using private key for account: ${deployer.address}`); // Use default hardhat account for local testing
[deployer] = await ethers.getSigners();
console.log(`Using default hardhat account: ${deployer.address}`);
} else {
const wallet = new ethers.Wallet(privateKey, ethers.provider);
deployer = wallet.connect(ethers.provider);
console.log(`Using private key for account: ${deployer.address}`);
}
console.log("Deploying contracts with the account:", deployer.address); console.log("Deploying contracts with the account:", deployer.address);
let deploymentData = {}; let deploymentData = {};
@@ -19,12 +26,25 @@ async function main() {
deploymentData = JSON.parse(fs.readFileSync(deploymentFile, "utf8")); deploymentData = JSON.parse(fs.readFileSync(deploymentFile, "utf8"));
} }
const contractName = network === "mainnet" // Select contract and proxy address based on network
? "PacaFinanceWithBoostAndScheduleUSDT" let contractName;
: "PacaFinanceWithBoostAndScheduleUSDC";
let proxyAddress; let proxyAddress;
if (!deploymentData.proxyAddress) { if (network === "base") {
contractName = "PacaFinanceWithBoostAndScheduleBase";
proxyAddress = process.env.PROXY_ADDRESS_BASE;
} else if (network === "sonic") {
contractName = "PacaFinanceWithBoostAndScheduleSonic";
proxyAddress = process.env.PROXY_ADDRESS_SONIC || deploymentData.proxyAddress;
} else if (network === "mainnet") {
contractName = "PacaFinanceWithBoostAndScheduleBsc";
proxyAddress = process.env.PROXY_ADDRESS_BSC || deploymentData.proxyAddress;
} else {
// Default to BSC for other networks (like test networks)
contractName = "PacaFinanceWithBoostAndScheduleBsc";
proxyAddress = deploymentData.proxyAddress;
}
if (!proxyAddress) {
// Initial deployment // Initial deployment
console.log("Deploying proxy..."); console.log("Deploying proxy...");
const Paca = await ethers.getContractFactory(contractName, deployer); const Paca = await ethers.getContractFactory(contractName, deployer);
@@ -46,12 +66,9 @@ async function main() {
await verifyContract(implementationAddress, contractName); await verifyContract(implementationAddress, contractName);
} else { } else {
// Upgrade // Upgrade
proxyAddress = deploymentData.proxyAddress;
console.log("Upgrading proxy..."); console.log("Upgrading proxy...");
const Paca = await ethers.getContractFactory(contractName, deployer); const Paca = await ethers.getContractFactory(contractName, deployer);
// //commen tout for mainet
// await upgrades.forceImport(proxyAddress, Paca);
// Get current implementation for comparison // Get current implementation for comparison
const oldImplementationAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress); const oldImplementationAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress);

112
scripts/manualUpgrade.js Normal file
View File

@@ -0,0 +1,112 @@
const { ethers } = require("hardhat");
const fs = require("fs");
const path = require("path");
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const deploymentFile = path.join(__dirname, "deployedAddresses.json");
async function main() {
const privateKey = process.env.PRIVATE_KEY;
const network = await hre.network.name;
let deployer;
if (network === "hardhat" || network === "localhost") {
[deployer] = await ethers.getSigners();
console.log(`Using default hardhat account: ${deployer.address}`);
} else {
const wallet = new ethers.Wallet(privateKey, ethers.provider);
deployer = wallet.connect(ethers.provider);
console.log(`Using private key for account: ${deployer.address}`);
}
console.log("Deploying contracts with the account:", deployer.address);
// Select contract based on network
let contractName;
if (network === "base") {
contractName = "PacaFinanceWithBoostAndScheduleBase";
} else if (network === "sonic") {
contractName = "PacaFinanceWithBoostAndScheduleSonic";
} else if (network === "mainnet") {
contractName = "PacaFinanceWithBoostAndScheduleBsc";
} else {
contractName = "PacaFinanceWithBoostAndScheduleBsc";
}
console.log(`Deploying ${contractName} for network: ${network}`);
// Read deployment data
let deploymentData = {};
if (fs.existsSync(deploymentFile)) {
deploymentData = JSON.parse(fs.readFileSync(deploymentFile, "utf8"));
}
if (!deploymentData.proxyAddress) {
console.error("No proxy address found in deployment file!");
process.exit(1);
}
const proxyAddress = deploymentData.proxyAddress;
console.log("Proxy address:", proxyAddress);
// Deploy new implementation contract
console.log("Deploying new implementation contract...");
const PacaFactory = await ethers.getContractFactory(contractName, deployer);
const newImplementation = await PacaFactory.deploy();
await newImplementation.waitForDeployment();
const newImplementationAddress = await newImplementation.getAddress();
console.log("New implementation deployed to:", newImplementationAddress);
// ProxyAdmin contract address
const proxyAdminAddress = "0x3459Fe72D4274d40d449aE1806F8E2149302F28B";
// ProxyAdmin ABI with upgradeAndCall function
const proxyAdminABI = [
"function upgradeAndCall(address proxy, address implementation, bytes data) external payable"
];
// Connect to ProxyAdmin contract
const proxyAdmin = new ethers.Contract(proxyAdminAddress, proxyAdminABI, deployer);
// Perform upgrade with empty call data
console.log("Performing upgrade via ProxyAdmin...");
console.log("ProxyAdmin address:", proxyAdminAddress);
const upgradeTx = await proxyAdmin.upgradeAndCall(proxyAddress, newImplementationAddress, "0x");
console.log("Upgrade transaction hash:", upgradeTx.hash);
// Wait for transaction confirmation
await upgradeTx.wait();
console.log("Upgrade completed successfully!");
// Update deployment data
deploymentData.implementationAddress = newImplementationAddress;
fs.writeFileSync(deploymentFile, JSON.stringify(deploymentData, null, 2));
console.log("Deployment data updated");
// Verify the new implementation
console.log("Waiting 10 seconds before verification...");
await new Promise(resolve => setTimeout(resolve, 10000));
try {
await hre.run("verify:verify", {
address: newImplementationAddress,
constructorArguments: []
});
console.log("Contract verified successfully.");
} catch (err) {
if (err.message.includes("already been verified")) {
console.log("Contract is already verified.");
} else {
console.log("Verification failed:", err.message);
console.log(`\nTo verify manually, run:`);
console.log(`npx hardhat verify --network ${network} ${newImplementationAddress}`);
}
}
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});