Skip to content

Commit cd52775

Browse files
Axel ValavaaraAxel Valavaara
authored andcommitted
Minting A3A and PyUsd for local testing. Added getA3ATokenAddress getter. Removed unnecessary data looping
1 parent 14831ee commit cd52775

6 files changed

Lines changed: 58 additions & 118 deletions

File tree

makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
-include .env
22
.PHONY: all test deploy
33

4-
deploy :; forge script script/DeployOrderContract.s.sol:DeployOrderContract --rpc-url http://127.0.0.1:8545
4+
deploy :; forge script script/DeployOrderContract.s.sol:DeployOrderContract --rpc-url 127.0.0.1:8545 --broadcast --private-key $(DEFAULT_ANVIL_KEY) -vvvv

script/DeployOrderContract.s.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@ contract DeployOrderContract is Script {
2020
OrderContract orderContract = new OrderContract(
2121
agentController, pyUSD, address(token) // Replace with actual pyUSD token address
2222
);
23+
if (block.chainid == 31337) {
24+
25+
token.mint(vm.envAddress("PUBLIC_KEY"), 1000000 ether);
26+
27+
}
2328
token.transferOwnership(address(orderContract));
29+
30+
2431

2532
vm.stopBroadcast();
2633
return (orderContract, helperConfig, token);

script/HelperConfig.s.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pragma solidity ^0.8.18;
55

66
import {Script} from "forge-std/Script.sol";
77
import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol";
8+
89
contract HelperConfig is Script {
910

1011
struct NetworkConfig {
@@ -29,12 +30,13 @@ contract HelperConfig is Script {
2930
}
3031
vm.startBroadcast();
3132
ERC20Mock pyUSD = new ERC20Mock();
33+
pyUSD.mint(vm.envAddress("PUBLIC_KEY"), 100 ether);
3234

3335
vm.stopBroadcast();
3436
return NetworkConfig({
3537
pyUSD: address(pyUSD),
3638
agentController: address(5),
37-
deployerKey: vm.envUint("PRIVATE_KEY")
39+
deployerKey: vm.envUint("DEFAULT_ANVIL_KEY")
3840
});
3941

4042
}

src/A3Atoken.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ contract A3AToken is ERC20Burnable, Ownable {
3434
error A3AToken__MintToTheZeroAddress();
3535
error A3AToken__MintAmountMustBeMoreThanZero();
3636

37-
constructor() ERC20("Decentralized Stable Coin", "DSC") Ownable(msg.sender) {}
37+
constructor() ERC20("A3A Token", "A3A") Ownable(msg.sender) {}
3838

3939
function burn(uint256 _amount) public override onlyOwner {
4040
uint256 balance = balanceOf(msg.sender);

src/OrderContract.sol

Lines changed: 21 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,10 @@ contract OrderContract is ReentrancyGuard{
6767
address private immutable pyUSD; // Address of the pyUSD token contract
6868
address private immutable a3aToken; // Address of the A3A token contract
6969

70-
// will make mappings to struct!!! thus too messy.
71-
//////////////////////////////////////////////
72-
// FIX THIS!!!!
73-
///////////////////////////////////
74-
// mapping(address => mapping(uint64 offerId => bytes32 promptHash)) private addressToOfferIdToPromptHash;
75-
// mapping(uint64 offerId => uint256 timestamp) private offerIdToTimestamp;
76-
// mapping(uint64 offerId => mapping(address user => uint256 amountPaid)) private offerIdToUserToAmountPaid;
77-
// mapping(uint64 offerId => OrderStatus status) private offerIdToStatus;
78-
// mapping(uint64 offerId => bytes32 answerHash) private offerIdToAnswerHash;
79-
// mapping(uint64 => address) private offerIdToUser;
8070

8171
mapping(uint64 => Offer) public offers;
8272

83-
// User order tracking mappings
84-
mapping(address => mapping(uint64 => bool)) private userOrders;
73+
8574
mapping(address => uint64[]) private userOrderIds;
8675

8776
// merchants address->orderIds mapping to fetch all orders for a merchant
@@ -125,11 +114,9 @@ contract OrderContract is ReentrancyGuard{
125114
offers[offerID].promptHash = promptHash;
126115

127116
// Update user order mappings
128-
userOrders[userWalletAddress][offerID] = true;
117+
129118
userOrderIds[userWalletAddress].push(offerID);
130-
131-
// addressToOfferIdToPromptHash[msg.sender][offerID] = promptHash;
132-
// offerIdToUser[offerID] = msg.sender;
119+
133120

134121
emit OrderProposed(offers[offerID].buyer, offerID, offers[offerID].promptHash);
135122
// Burn 10 A3A tokens from uses. This acts as Fee for using the platform.
@@ -155,12 +142,10 @@ contract OrderContract is ReentrancyGuard{
155142
}
156143
// update amount paid for the offer by the user
157144
uint256 amountToPay = offers[offerId].price + AGENT_FEE;
158-
// offerIdToUserToAmountPaid[offerId][msg.sender] += amountToPay;
159-
// offerIdToStatus[offerId] = OrderStatus.Confirmed;
145+
160146
offers[offerId].paid = amountToPay;
161147
offers[offerId].status = OrderStatus.Confirmed;
162-
// Record the current timestamp for the offer
163-
// offerIdToTimestamp[offerId] = block.timestamp;
148+
164149
offers[offerId].timestamp = block.timestamp;
165150
bool success= ERC20(pyUSD).transferFrom(msg.sender, address(this), amountToPay);
166151

@@ -277,6 +262,10 @@ contract OrderContract is ReentrancyGuard{
277262
return offers[orderId];
278263
}
279264

265+
function getA3ATokenAddress() external view returns (address) {
266+
return a3aToken;
267+
}
268+
280269
// User order query functions for backend integration
281270

282271
/**
@@ -294,8 +283,12 @@ contract OrderContract is ReentrancyGuard{
294283
* @param orderId The order ID to check
295284
* @return bool indicating if the user has this order
296285
*/
297-
function hasUserOrder(address user, uint64 orderId) external view returns (bool) {
298-
return userOrders[user][orderId];
286+
function hasUserOrder(address user, uint64 orderId) public view returns (bool) {
287+
if (offers[orderId].buyer == user) {
288+
return true;
289+
} else {
290+
return false;
291+
}
299292
}
300293

301294
/**
@@ -311,23 +304,8 @@ contract OrderContract is ReentrancyGuard{
311304
// require(userOrders[user][orderId], "Order does not belong to user");
312305
return offers[orderId].status;
313306
}
307+
314308

315-
/**
316-
* @notice Get all orders with their statuses for a specific user
317-
* @param user The user address to query
318-
* @return orderIds Array of order IDs
319-
* @return statuses Array of corresponding order statuses
320-
*/
321-
function getUserOrdersWithStatus(address user) external view returns (uint64[] memory orderIds, OrderStatus[] memory statuses) {
322-
uint64[] memory userIds = userOrderIds[user];
323-
OrderStatus[] memory orderStatuses = new OrderStatus[](userIds.length);
324-
325-
for (uint256 i = 0; i < userIds.length; i++) {
326-
orderStatuses[i] = offers[userIds[i]].status;
327-
}
328-
329-
return (userIds, orderStatuses);
330-
}
331309

332310
/**
333311
* @notice Get complete order details for a user's specific order
@@ -336,36 +314,14 @@ contract OrderContract is ReentrancyGuard{
336314
* @return Complete Offer struct for the specified order
337315
*/
338316
function getUserOrderDetails(address user, uint64 orderId) external view returns (Offer memory) {
339-
require(userOrders[user][orderId], "Order does not belong to user");
317+
if (hasUserOrder(user, orderId) == false) {
318+
revert OrderContract__userHasNoAccessToOffer();
319+
}
340320
return offers[orderId];
341321
}
342322

343-
/**
344-
* @notice Get orders filtered by status for a user
345-
* @param user The user address
346-
* @param status The status to filter by
347-
* @return Array of order IDs matching the specified status
348-
*/
349-
function getUserOrdersByStatus(address user, OrderStatus status) external view returns (uint64[] memory) {
350-
uint64[] memory userIds = userOrderIds[user];
351-
uint64[] memory filteredIds = new uint64[](userIds.length);
352-
uint256 count = 0;
353-
354-
for (uint256 i = 0; i < userIds.length; i++) {
355-
if (offers[userIds[i]].status == status) {
356-
filteredIds[count] = userIds[i];
357-
count++;
358-
}
359-
}
360-
361-
// Create a properly sized array
362-
uint64[] memory result = new uint64[](count);
363-
for (uint256 i = 0; i < count; i++) {
364-
result[i] = filteredIds[i];
365-
}
366-
367-
return result;
368-
}
323+
324+
369325

370326

371327
}

test/unit/OrderContractTest.t.sol

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -372,29 +372,7 @@ contract OrderContractTest is Test {
372372
assertEq(uint8(status), uint8(OrderContract.OrderStatus.InProgress));
373373
}
374374

375-
function testGetUserOrdersWithStatus() public {
376-
// Arrange
377-
bytes32 testPromptHash1 = keccak256(abi.encodePacked("Test Prompt 1"));
378-
bytes32 testPromptHash2 = keccak256(abi.encodePacked("Test Prompt 2"));
379-
380-
vm.prank(USER);
381-
ERC20Mock(pyUSD).approve(address(orderContract), amountForCompute * 2);
382-
vm.startPrank(addressController);
383-
uint64 offerId1 = orderContract.proposeOrder(testPromptHash1, USER);
384-
uint64 offerId2 = orderContract.proposeOrder(testPromptHash2, USER);
385-
vm.stopPrank();
386-
387-
// Act
388-
(uint64[] memory orderIds, OrderContract.OrderStatus[] memory statuses) = orderContract.getUserOrdersWithStatus(USER);
389-
390-
// Assert
391-
assertEq(orderIds.length, 2);
392-
assertEq(statuses.length, 2);
393-
assertEq(orderIds[0], offerId1);
394-
assertEq(orderIds[1], offerId2);
395-
assertEq(uint8(statuses[0]), uint8(OrderContract.OrderStatus.InProgress));
396-
assertEq(uint8(statuses[1]), uint8(OrderContract.OrderStatus.InProgress));
397-
}
375+
398376

399377
function testGetUserOrderDetails() public {
400378
// Arrange
@@ -415,34 +393,9 @@ contract OrderContractTest is Test {
415393
assertEq(uint8(offer.status), uint8(OrderContract.OrderStatus.InProgress));
416394
}
417395

418-
function testGetUserOrdersByStatus() public proposeOrderForUser {
419-
// Arrange - we already have one order in InProgress from the modifier
420-
uint64 initialOfferId = 1;
421-
422-
// Propose answer to move to Proposed status
423-
vm.prank(addressController);
424-
orderContract.proposeOrderAnswer(keccak256(abi.encodePacked("Test Answer")), initialOfferId, 5 ether, SELLER);
425-
426-
// Create another order that stays InProgress
427-
bytes32 testPromptHash2 = keccak256(abi.encodePacked("Test Prompt 2"));
428-
vm.prank(USER);
429-
ERC20Mock(pyUSD).approve(address(orderContract), amountForCompute);
430-
vm.startPrank(addressController);
431-
uint64 offerId2 = orderContract.proposeOrder(testPromptHash2, USER);
432-
vm.stopPrank();
433-
434-
// Act
435-
uint64[] memory proposedOrders = orderContract.getUserOrdersByStatus(USER, OrderContract.OrderStatus.Proposed);
436-
uint64[] memory inProgressOrders = orderContract.getUserOrdersByStatus(USER, OrderContract.OrderStatus.InProgress);
437-
438-
// Assert
439-
assertEq(proposedOrders.length, 1);
440-
assertEq(proposedOrders[0], initialOfferId);
441-
assertEq(inProgressOrders.length, 1);
442-
assertEq(inProgressOrders[0], offerId2);
443-
}
396+
444397

445-
function testHasUserOrderReturnsFalseForNonExistentOrder() public {
398+
function testHasUserOrderReturnsFalseForNonExistentOrder() public view {
446399
// Act & Assert
447400
assertFalse(orderContract.hasUserOrder(USER, 999));
448401
}
@@ -462,4 +415,26 @@ contract OrderContractTest is Test {
462415
orderContract.getUserOrderStatus(otherUser, offerId);
463416
}
464417

418+
function testUserGetsMintedBalance() public view {
419+
// Arrange
420+
uint256 expectedBalance = 1000000 ether; // 10e6 pyUSD buys 100 A3A tokens
421+
422+
// Act
423+
uint256 userBalance = a3aToken.balanceOf(vm.envAddress("PUBLIC_KEY"));
424+
425+
// Assert
426+
assertEq(userBalance, expectedBalance);
427+
}
428+
429+
function testUserGetsMintedPyUsd() public view {
430+
// Arrange
431+
uint256 expectedBalance = 100 ether; // Anvil setup mints 100 pyUSD to PUBLIC_KEY
432+
433+
// Act
434+
uint256 userBalance = ERC20Mock(pyUSD).balanceOf(vm.envAddress("PUBLIC_KEY"));
435+
436+
// Assert
437+
assertEq(userBalance, expectedBalance);
438+
}
439+
465440
}

0 commit comments

Comments
 (0)