Skip to content

Commit 7571959

Browse files
committed
Add scripts for deploy swan impl + test
1 parent 13648a7 commit 7571959

7 files changed

+196
-0
lines changed

script/Deploy.s.sol

+9
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ contract DeploySwan is Script {
6262
}
6363
}
6464

65+
contract DeploySwanImpl is Script {
66+
HelperConfig public config;
67+
68+
function run() external returns (address addr) {
69+
config = new HelperConfig();
70+
addr = config.deploySwanImpl();
71+
}
72+
}
73+
6574
contract DeploySwanLottery is Script {
6675
HelperConfig public config;
6776

script/HelperConfig.s.sol

+9
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ contract HelperConfig is Script {
199199
return (swanProxy, swanImplementation);
200200
}
201201

202+
function deploySwanImpl() external returns (address impl) {
203+
vm.startBroadcast();
204+
Swan newImplementation = new Swan();
205+
vm.stopBroadcast();
206+
207+
// console.log("New implementation address:", address(newImplementation));
208+
return address(newImplementation);
209+
}
210+
202211
function deploySwanLottery() external returns (address) {
203212
// read Swan proxy address from deployments file
204213
string memory dir = "deployments/";

test/SwanUpgradeTest.t.sol

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {Test, console} from "forge-std/Test.sol";
5+
import {Swan} from "../src/Swan.sol";
6+
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
7+
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
8+
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
9+
import {SwanManager, SwanMarketParameters} from "../src/SwanManager.sol";
10+
import {LLMOracleTaskParameters} from "@firstbatch/dria-oracle-contracts/LLMOracleCoordinator.sol";
11+
import {MockERC20} from "./mock/MockERC20.sol";
12+
import {MockLLMOracleCoordinator} from "./mock/MockLLMOracleCoordinator.sol";
13+
import {MockSwanAgentFactory} from "./mock/MockSwanAgentFactory.sol";
14+
import {MockSwanArtifactFactory} from "./mock/MockSwanArtifactFactory.sol";
15+
16+
contract SwanUpgradeTest is Test {
17+
Swan swanImplementationV1;
18+
Swan proxy;
19+
20+
MockERC20 token;
21+
MockLLMOracleCoordinator coordinator;
22+
MockSwanAgentFactory agentFactory;
23+
MockSwanArtifactFactory artifactFactory;
24+
25+
address owner = address(0x1);
26+
address user = address(0x2);
27+
28+
function setUp() public {
29+
// Deploy mock dependencies
30+
token = new MockERC20("Test Token", "TEST");
31+
coordinator = new MockLLMOracleCoordinator();
32+
agentFactory = new MockSwanAgentFactory();
33+
artifactFactory = new MockSwanArtifactFactory();
34+
35+
vm.startPrank(owner);
36+
37+
// Deploy the original implementation
38+
swanImplementationV1 = new Swan();
39+
40+
SwanMarketParameters memory marketParams = SwanMarketParameters({
41+
withdrawInterval: 1 days,
42+
listingInterval: 2 days,
43+
buyInterval: 3 days,
44+
platformFee: 10,
45+
maxArtifactCount: 10,
46+
minArtifactPrice: 1 ether,
47+
timestamp: block.timestamp,
48+
maxAgentFee: 20
49+
});
50+
51+
LLMOracleTaskParameters memory oracleParams =
52+
LLMOracleTaskParameters({difficulty: 1, numGenerations: 1, numValidations: 1});
53+
54+
bytes memory initData = abi.encodeCall(
55+
Swan.initialize,
56+
(
57+
marketParams,
58+
oracleParams,
59+
address(coordinator),
60+
address(token),
61+
address(agentFactory),
62+
address(artifactFactory)
63+
)
64+
);
65+
66+
// Deploy the proxy with the implementation and initialization data
67+
ERC1967Proxy proxyContract = new ERC1967Proxy(address(swanImplementationV1), initData);
68+
69+
// Cast the proxy to Swan for easier interaction
70+
proxy = Swan(address(proxyContract));
71+
72+
vm.stopPrank();
73+
74+
// Verify initial setup
75+
assertEq(proxy.owner(), owner);
76+
}
77+
78+
function testUpgrade() public {
79+
// Pre-upgrade checks
80+
assertEq(address(proxy.agentFactory()), address(agentFactory));
81+
assertEq(address(proxy.artifactFactory()), address(artifactFactory));
82+
83+
// Deploy the new implementation
84+
vm.startPrank(owner);
85+
Swan swanImplementationV2 = new Swan();
86+
87+
proxy.upgradeToAndCall(address(swanImplementationV2), "");
88+
vm.stopPrank();
89+
90+
// Get implementation address
91+
bytes32 implementationSlot = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
92+
bytes32 implementationValue = vm.load(address(proxy), implementationSlot);
93+
address currentImplementation = address(uint160(uint256(implementationValue)));
94+
95+
assertEq(currentImplementation, address(swanImplementationV2));
96+
97+
// Post-upgrade checks to ensure all state is preserved
98+
assertEq(address(proxy.agentFactory()), address(agentFactory));
99+
assertEq(address(proxy.artifactFactory()), address(artifactFactory));
100+
101+
// Test functionality after upgrade
102+
vm.startPrank(owner);
103+
address newAgentFactory = address(new MockSwanAgentFactory());
104+
address newArtifactFactory = address(new MockSwanArtifactFactory());
105+
proxy.setFactories(newAgentFactory, newArtifactFactory);
106+
vm.stopPrank();
107+
108+
// Verify the new factories were set correctly
109+
assertEq(address(proxy.agentFactory()), newAgentFactory);
110+
assertEq(address(proxy.artifactFactory()), newArtifactFactory);
111+
}
112+
113+
// Test that the upgrade fails if called by a non-owner
114+
function testUpgradeFailsWhenCalledByNonOwner() public {
115+
vm.startPrank(owner);
116+
Swan swanImplementationV2 = new Swan();
117+
vm.stopPrank();
118+
119+
// Try to upgrade from a non-owner account
120+
vm.startPrank(user);
121+
vm.expectRevert(); // Should revert due to onlyOwner
122+
proxy.upgradeToAndCall(address(swanImplementationV2), "");
123+
vm.stopPrank();
124+
}
125+
}

test/mock/MockERC20.sol

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5+
6+
contract MockERC20 is ERC20 {
7+
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
8+
_mint(msg.sender, 1000000 * 10 ** 18);
9+
}
10+
11+
function mint(address to, uint256 amount) public {
12+
_mint(to, amount);
13+
}
14+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {LLMOracleCoordinator} from "@firstbatch/dria-oracle-contracts/LLMOracleCoordinator.sol";
5+
6+
contract MockLLMOracleCoordinator {
7+
// Mock functions as needed
8+
}

test/mock/MockSwanAgentFactory.sol

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {SwanAgentFactory, SwanAgent} from "../../src/SwanAgent.sol";
5+
6+
contract MockSwanAgentFactory {
7+
function deploy(
8+
string calldata _name,
9+
string calldata _description,
10+
uint96 _listingFee,
11+
uint256 _amountPerRound,
12+
address _owner
13+
) external returns (SwanAgent) {
14+
// Return a mock agent
15+
return SwanAgent(address(0));
16+
}
17+
}

test/mock/MockSwanArtifactFactory.sol

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {SwanArtifactFactory, SwanArtifact} from "../../src/SwanArtifact.sol";
5+
6+
contract MockSwanArtifactFactory {
7+
function deploy(string calldata _name, string calldata _symbol, bytes calldata _desc, address _owner)
8+
external
9+
returns (SwanArtifact)
10+
{
11+
// Return a mock artifact
12+
return SwanArtifact(address(0));
13+
}
14+
}

0 commit comments

Comments
 (0)