Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@
[submodule "lib/hamza-escrow"]
path = lib/hamza-escrow
url = https://github.com/LoadPipe/hamza-escrow
branch = HAMT-75-purchase-tracker-currency
2 changes: 1 addition & 1 deletion lib/hamza-escrow
33 changes: 29 additions & 4 deletions scripts/DeployHamzaVault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import "../src/GovernanceVault.sol";
import "@hamza-escrow/SystemSettings.sol";
import "@hamza-escrow/PaymentEscrow.sol";
import "@hamza-escrow/EscrowMulticall.sol";
import { TestToken as HamzaTestToken } from "@hamza-escrow/TestToken.sol";

import "../src/HamzaGovernor.sol";
import { HamzaGovernor } from "../src/HamzaGovernor.sol";
Expand Down Expand Up @@ -58,6 +59,9 @@ contract DeployHamzaVault is Script {

address public escrowAddr;

// Add testToken address
address public testTokenAddr;

// Store these values to avoid stack depth issues
address public safeAddr;
address public hats;
Expand All @@ -75,7 +79,8 @@ contract DeployHamzaVault is Script {
address governanceToken,
address governanceVault,
address _safeAddress,
address _hatsSecurityContext
address _hatsSecurityContext,
address testToken
)
{
// 1) Read config file
Expand Down Expand Up @@ -138,6 +143,9 @@ contract DeployHamzaVault is Script {
// 15-16) Deploy PurchaseTracker, PaymentEscrow, and EscrowMulticall
deployEscrowContracts(ISecurityContext(hatsSecurityContextAddr), vault, lootTokenAddr);

// 17) Deploy TestToken
address _testTokenAddr = deployTestToken();

vm.stopBroadcast();

if (keccak256(abi.encodePacked(mode)) == keccak256(abi.encodePacked("Deploy"))) {
Expand All @@ -146,7 +154,8 @@ contract DeployHamzaVault is Script {
vault,
govTokenAddr,
govVaultAddr,
timelockAddr
timelockAddr,
_testTokenAddr
);
}

Expand All @@ -157,7 +166,8 @@ contract DeployHamzaVault is Script {
govTokenAddr, // governanceToken
govVaultAddr, // governanceVault
safeAddr, // safeAddress
hatsSecurityContextAddr // hatsSecurityContext
hatsSecurityContextAddr, // hatsSecurityContext
_testTokenAddr // testToken
);
}

Expand Down Expand Up @@ -439,12 +449,26 @@ contract DeployHamzaVault is Script {
new EscrowMulticall();
}

function deployTestToken() internal returns (address) {
// Deploy TestToken with name and symbol
HamzaTestToken testToken = new HamzaTestToken("Hamza Test Token", "HTT");

// Store the address
testTokenAddr = address(testToken);

// Mint some tokens to OWNER_ONE for testing
testToken.mint(OWNER_ONE, 1000 * 10**18);

return testTokenAddr;
}

function logDeployedAddresses(
address newBaalAddr,
address communityVault,
address govTokenAddr,
address govVaultAddr,
address timelockAddr
address timelockAddr,
address _testTokenAddr
) internal view {
console2.log("Owner One (from PRIVATE_KEY):", OWNER_ONE);
console2.log("Owner Two (from config): ", OWNER_TWO);
Expand All @@ -464,6 +488,7 @@ contract DeployHamzaVault is Script {
console2.log("Timelock deployed at:", timelockAddr);
console2.log("PurchaseTracker deployed at:", purchaseTrackerAddr);
console2.log("PaymentEscrow deployed at:", escrowAddr);
console2.log("TestToken deployed at:", _testTokenAddr);
console2.log("-----------------------------------------------");
}

Expand Down
39 changes: 34 additions & 5 deletions src/PurchaseTracker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ contract PurchaseTracker is HasSecurityContext, IPurchaseTracker {
// Mapping from buyer address to cumulative purchase count and total purchase amount.
mapping(address => uint256) public totalPurchaseCount;
mapping(address => uint256) public totalPurchaseAmount;

mapping(address => mapping(address => uint256)) public purchaseAmountByCurrency;

// mapping for sellers
mapping(address => uint256) public totalSalesCount;
mapping(address => uint256) public totalSalesAmount;
mapping(address => mapping(address => uint256)) public salesAmountByCurrency;

// Store details about each purchase (keyed by the unique payment ID).
mapping(bytes32 => Purchase) public purchases;
Expand All @@ -32,13 +34,14 @@ contract PurchaseTracker is HasSecurityContext, IPurchaseTracker {
address seller;
address buyer;
uint256 amount;
address currency;
bool recorded;
}

// Authorized contracts (such as escrow contracts) that are allowed to record purchases.
mapping(address => bool) public authorizedEscrows;

event PurchaseRecorded(bytes32 indexed paymentId, address indexed buyer, uint256 amount);
event PurchaseRecorded(bytes32 indexed paymentId, address indexed buyer, uint256 amount, address currency);

modifier onlyAuthorized() {
require(authorizedEscrows[msg.sender], "PurchaseTracker: Not authorized");
Expand Down Expand Up @@ -69,26 +72,44 @@ contract PurchaseTracker is HasSecurityContext, IPurchaseTracker {
/**
* @notice Records a purchase.
* @param paymentId The unique payment ID.
* @param buyer The address of the buyer
* @param seller The address of the seller
* @param buyer The address of the buyer
* @param amount The purchase amount.
* @param currency The currency used for the purchase.
*
* Requirements:
* - The caller must be an authorized contract.
* - A purchase with the same paymentId must not have been recorded already.
*/
function recordPurchase(bytes32 paymentId, address seller, address buyer, uint256 amount, address currency) external onlyAuthorized {
_recordPurchase(paymentId, seller, buyer, amount, currency);
}

/**
* @notice Legacy recordPurchase function for backward compatibility.
* Now calls the new function with a default currency of address(0).
*/
function recordPurchase(bytes32 paymentId, address seller, address buyer, uint256 amount) external onlyAuthorized {
_recordPurchase(paymentId, seller, buyer, amount, address(0));
}

/**
* @dev Internal implementation of recordPurchase that both external functions call.
*/
function _recordPurchase(bytes32 paymentId, address seller, address buyer, uint256 amount, address currency) internal {
require(!purchases[paymentId].recorded, "PurchaseTracker: Purchase already recorded");

purchases[paymentId] = Purchase(seller, buyer, amount, true);
purchases[paymentId] = Purchase(seller, buyer, amount, currency, true);
totalPurchaseCount[buyer] += 1;
totalPurchaseAmount[buyer] += amount;
purchaseAmountByCurrency[buyer][currency] += amount;

//log seller info
totalSalesCount[seller] += 1;
totalSalesAmount[seller] += amount;
salesAmountByCurrency[seller][currency] += amount;

emit PurchaseRecorded(paymentId, buyer, amount);
emit PurchaseRecorded(paymentId, buyer, amount, currency);
}

function getPurchaseCount(address recipient) external view returns (uint256) {
Expand All @@ -106,4 +127,12 @@ contract PurchaseTracker is HasSecurityContext, IPurchaseTracker {
function getSalesAmount(address recipient) external view returns (uint256) {
return totalSalesAmount[recipient];
}

function getPurchaseAmountByCurrency(address recipient, address currency) external view returns (uint256) {
return purchaseAmountByCurrency[recipient][currency];
}

function getSalesAmountByCurrency(address recipient, address currency) external view returns (uint256) {
return salesAmountByCurrency[recipient][currency];
}
}
3 changes: 2 additions & 1 deletion test/DeploymentSetup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ contract DeploymentSetup is Test {
address public systemSettings;
address public purchaseTracker;
address public escrow;
address public deployedTestToken;
uint256 public adminHatId;
address public admin;
address public lootToken;
Expand Down Expand Up @@ -56,7 +57,7 @@ contract DeploymentSetup is Test {

// Deploy contracts
script = new DeployHamzaVault();
(baal, communityVault, govToken, govVault, safe, hatsCtx) = script.run();
(baal, communityVault, govToken, govVault, safe, hatsCtx, deployedTestToken) = script.run();

// Initialize addresses
adminHatId = script.adminHatId();
Expand Down
Loading