Skip to content

Commit 339ef06

Browse files
authored
Merge pull request #54 from district0x/multichain-pools
Enable multichain pools in QA
2 parents 0c21005 + 24167a0 commit 339ef06

34 files changed

+3993
-2493
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/.idea/
22
/streamtide.iml
33
/config.edn
4+
/config*.edn
45
/resources/public/js/main.js
56
/resources/public/js/cljs-runtime/
67
/resources/public/js/manifest.edn
@@ -14,3 +15,4 @@
1415
/.shadow-cljs/
1516
/server/
1617
/target/
18+
/ecosystem.config.js

bb.edn

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,24 @@
4141
command-args (format "-M:dev:shadow-cljs%s watch server" (clojure.string.join "" aliases))]
4242
(println "Starting watch server args:" command-args)
4343
(clojure command-args))}
44+
watch-sidechain-server {:doc "Watch and compile sidechain server code changes CLJS -> JS in src/server/**"
45+
:requires ([babashka.cli :as cli])
46+
:task (let [aliases (or *command-line-args* [])
47+
command-args (format "-M:dev:shadow-cljs%s watch sidechain-server" (clojure.string.join "" aliases))]
48+
(println "Starting watch sidechain server args:" command-args)
49+
(clojure command-args))}
4450
release-server {:doc "Compile server CLJS -> JS in src/server/** for release"
4551
:requires ([babashka.cli :as cli])
4652
:task (let [aliases (or *command-line-args* [])
4753
command-args (format "-M:shadow-cljs%s release server" (clojure.string.join "" aliases))]
4854
(println "Preparing server for release:" command-args)
4955
(clojure command-args))}
56+
release-sidechain-server {:doc "Compile sidechain server CLJS -> JS in src/server/** for release"
57+
:requires ([babashka.cli :as cli])
58+
:task (let [aliases (or *command-line-args* [])
59+
command-args (format "-M:shadow-cljs%s release sidechain-server" (clojure.string.join "" aliases))]
60+
(println "Preparing sidechain server for release:" command-args)
61+
(clojure command-args))}
5062
watch-ui-server {:doc "Watch and compile both ui and server code changes CLJS -> JS in src/(ui|server)/**"
5163
:requires ([babashka.cli :as cli])
5264
:task (let [aliases (or *command-line-args* [])
@@ -57,6 +69,11 @@
5769
:task (do
5870
(println "Starting Streamtide API server")
5971
(shell "node server/streamtide_server.js"))}
72+
run-sidechain-server {:doc "Start Node.js API sidechain server process"
73+
:task (let [command-args (clojure.string.join " " (or *command-line-args* []))]
74+
(do
75+
(println "Starting Streamtide sidechain server")
76+
(shell (format "node sidechain_server/streamtide_sidechain_server.js %s" command-args))))}
6077
watch-server-tests {:doc "watch server tests"
6178
:task (do
6279
(println "Watch and compile server code changes tests")

contracts/MatchingPool.sol

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
6+
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
7+
import "@openzeppelin/contracts/utils/Context.sol";
8+
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
9+
10+
11+
contract MatchingPool is OwnableUpgradeable {
12+
13+
event AdminAdded(address _admin);
14+
event AdminRemoved(address _admin);
15+
event MatchingPoolFilled(uint256 amount);
16+
17+
event MatchingPoolDonation(address sender, uint256 value, uint256 roundId);
18+
event MatchingPoolDonationToken(address sender, uint256 value, uint256 roundId, address token);
19+
event Distribute(address to, uint256 amount, uint256 roundId, address token);
20+
event DistributeRound(uint256 roundId, uint256 amount, address token);
21+
22+
mapping(address => bool) public isAdmin;
23+
24+
address public multisigAddress;
25+
26+
function construct(address _multisigAddress) external initializer {
27+
__Ownable_init(); // Add this line to initialize the OwnableUpgradeable contract
28+
multisigAddress = _multisigAddress;
29+
}
30+
31+
function setMultisigAddress(address _multisigAddress) external onlyMultisig {
32+
multisigAddress = _multisigAddress;
33+
}
34+
35+
function fillUpMatchingPool(uint256 roundId) public payable onlyAdmin {
36+
require(msg.value > 0, "MVPCLR:fillUpMatchingPool - No value provided");
37+
emit MatchingPoolDonation(msg.sender, msg.value, roundId);
38+
}
39+
40+
function fillUpMatchingPoolToken(address from, address token, uint amount, uint256 roundId) public onlyAdmin {
41+
require(amount > 0, "MVPCLR:fillUpMatchingPoolToken - No amount provided");
42+
43+
IERC20(token).transferFrom(from, address(this), amount);
44+
45+
emit MatchingPoolDonationToken(from, amount, roundId, token);
46+
}
47+
48+
function addAdmin(address _admin) public onlyOwner {
49+
isAdmin[_admin] = true;
50+
emit AdminAdded(_admin);
51+
}
52+
53+
function removeAdmin(address _admin) public onlyOwner {
54+
require(isAdmin[_admin], "Admin not found");
55+
delete isAdmin[_admin];
56+
emit AdminRemoved(_admin);
57+
}
58+
59+
function distribute(address payable[] memory patrons, uint[] memory amounts, address token, uint256 roundId) public onlyAdmin {
60+
require(patrons.length == amounts.length, "Length of patrons and amounts must be the same");
61+
uint256 totalAmount = 0; // Store total amount to be distributed
62+
63+
// Loop through the list of patrons and distribute the funds to each address
64+
for (uint i = 0; i < patrons.length; i++) {
65+
if (token == address(0))
66+
patrons[i].transfer(amounts[i]); // Reverts transaction if transfer fails
67+
else
68+
IERC20(token).transfer(patrons[i], amounts[i]);
69+
emit Distribute(patrons[i], amounts[i], roundId, token);
70+
totalAmount += amounts[i]; // Add the amount to totalAmount
71+
}
72+
emit DistributeRound(roundId, totalAmount, token);
73+
}
74+
75+
function withdrawFunds(uint256 amount) external onlyMultisig {
76+
require(address(this).balance >= amount, "Insufficient funds in contract");
77+
payable(multisigAddress).transfer(amount);
78+
}
79+
80+
function withdrawERC20Funds(uint256 amount, address token) external onlyMultisig {
81+
IERC20(token).transfer(msg.sender, amount);
82+
}
83+
84+
modifier onlyAdmin() {
85+
require(isAdmin[msg.sender] == true, "Not an admin");
86+
_;
87+
}
88+
89+
modifier onlyMultisig() {
90+
require(msg.sender == multisigAddress, "Not authorized");
91+
_;
92+
}
93+
94+
}

docker-builds/server/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ bb release-server && \
1414
bb compile-contracts
1515

1616
EXPOSE 6300 3000
17-
ENTRYPOINT ["node", "server/streamtide_server.js"]
17+
ENTRYPOINT ["pm2-runtime", "start", "ecosystem.config.js"]

migrations/2_streamtide_contracts.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
const {Status, copy, linkBytecode, smartContractsTemplate} = require ("./utils.js");
2-
const fs = require('fs');
1+
const {Status, copy, linkBytecode, writeSmartContracts} = require ("./utils.js");
32
const edn = require("jsedn");
43
const {env, contracts_build_directory, smart_contracts_path, parameters} = require ('../truffle.js');
54

@@ -46,9 +45,7 @@ module.exports = async(deployer, network, accounts) => {
4645
await streamtideForwarder.construct(parameters.multiSig, parameters.lastRound);
4746
});
4847

49-
var smartContracts = edn.encode(
50-
new edn.Map([
51-
48+
var smartContracts = new edn.Map([
5249
edn.kw(":migrations"), new edn.Map([edn.kw(":name"), "Migrations",
5350
edn.kw(":address"), migrations.address]),
5451

@@ -58,10 +55,10 @@ module.exports = async(deployer, network, accounts) => {
5855
edn.kw(":streamtide-fwd"), new edn.Map([edn.kw(":name"), "MutableForwarder",
5956
edn.kw(":address"), status.getValue(sk.streamtideForwarderAddr),
6057
edn.kw(":forwards-to"), edn.kw(":streamtide")])
61-
]));
58+
]);
6259

6360
console.log (smartContracts);
64-
fs.writeFileSync(smart_contracts_path, smartContractsTemplate (smartContracts, env));
61+
writeSmartContracts(smart_contracts_path, smartContracts, new edn.Map(), env);
6562

6663
status.clean();
6764
console.log ("Done");

migrations/3_add_admins.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const {readSmartContractsFile, getSmartContractAddress} = require ("./utils.js");
22
const {smart_contracts_path, env, parameters} = require ('../truffle.js');
33

4-
const smartContracts = readSmartContractsFile(smart_contracts_path);
4+
const [smartContracts, _] = readSmartContractsFile(smart_contracts_path);
55
const streamtideFwdAddr = getSmartContractAddress(smartContracts, ":streamtide-fwd");
66

77
const Streamtide = artifacts.require("MVPCLR");

migrations/4_add_patrons.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const {readSmartContractsFile, getSmartContractAddress} = require ("./utils.js");
22
const {smart_contracts_path, env, parameters} = require ('../truffle.js');
33

4-
const smartContracts = readSmartContractsFile(smart_contracts_path);
4+
const [smartContracts, _] = readSmartContractsFile(smart_contracts_path);
55
const streamtideFwdAddr = getSmartContractAddress(smartContracts, ":streamtide-fwd");
66

77
const Streamtide = artifacts.require("MVPCLR");
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const {Status, copy, linkBytecode, readSmartContractsFile, writeSmartContracts} = require ("./utils.js");
2+
const edn = require("jsedn");
3+
const {env, contracts_build_directory, smart_contracts_path, parameters} = require ('../truffle.js');
4+
5+
copy ("MutableForwarder", "MatchingPoolForwarder", contracts_build_directory);
6+
const MatchingPoolForwarder = artifacts.require("MatchingPoolForwarder");
7+
const MatchingPool = artifacts.require("MatchingPool");
8+
9+
let [smartContracts, multichainSmartContracts] = readSmartContractsFile(smart_contracts_path);
10+
11+
const forwarderTargetPlaceholder = "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef";
12+
13+
module.exports = async(deployer, network, accounts) => {
14+
const address = accounts [0];
15+
const gas = 4e6;
16+
const opts = {gas: gas, from: address};
17+
18+
await deployer;
19+
20+
let status = new Status("5");
21+
22+
const sk = {
23+
matchingPoolAddr: "matchingPoolAddr",
24+
matchingPoolForwarderAddr: "matchingPoolForwarderAddr"
25+
}
26+
27+
await status.step(async () => {
28+
const matchingPool = await deployer.deploy(MatchingPool, Object.assign(opts, {gas: 20000000}));
29+
return {[sk.matchingPoolAddr]: matchingPool.address};
30+
});
31+
32+
await status.step(async () => {
33+
const matchingPoolAddr = status.getValue(sk.matchingPoolAddr);
34+
35+
linkBytecode(MatchingPoolForwarder, forwarderTargetPlaceholder, matchingPoolAddr);
36+
const matchingPoolForwarder = await deployer.deploy(MatchingPoolForwarder, Object.assign(opts, {gas: 5000000}));
37+
return {[sk.matchingPoolForwarderAddr]: matchingPoolForwarder.address};
38+
});
39+
40+
await status.step(async () => {
41+
const matchingPoolForwarderAddr = status.getValue(sk.matchingPoolForwarderAddr);
42+
43+
const matchingPoolForwarder = await MatchingPool.at(matchingPoolForwarderAddr);
44+
await matchingPoolForwarder.construct(parameters.multiSig);
45+
});
46+
47+
if (!multichainSmartContracts) {
48+
multichainSmartContracts = new edn.Map();
49+
}
50+
51+
multichainSmartContracts.set(edn.kw(":" + deployer.network_id),
52+
new edn.Map([
53+
edn.kw(":matching-pool"), new edn.Map([edn.kw(":name"), "MatchingPool",
54+
edn.kw(":address"), status.getValue(sk.matchingPoolAddr)]),
55+
56+
edn.kw(":matching-pool-fwd"), new edn.Map([edn.kw(":name"), "MutableForwarder",
57+
edn.kw(":address"), status.getValue(sk.matchingPoolForwarderAddr),
58+
edn.kw(":forwards-to"), edn.kw(":matching-pool")])
59+
]));
60+
61+
writeSmartContracts(smart_contracts_path, smartContracts, multichainSmartContracts, env);
62+
63+
status.clean();
64+
console.log ("Done");
65+
66+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const {readSmartContractsFile, getSmartContractAddress} = require ("./utils.js");
2+
const edn = require("jsedn");
3+
const {smart_contracts_path, parameters} = require ('../truffle.js');
4+
5+
const [_, multichainSmartContracts] = readSmartContractsFile(smart_contracts_path);
6+
7+
const MatchingPool = artifacts.require("MatchingPool");
8+
9+
module.exports = async(deployer, network, accounts) => {
10+
const address = accounts [0];
11+
const gas = 4e6;
12+
const opts = {gas: gas, from: address};
13+
14+
await deployer;
15+
16+
const chainSmartContracts = edn.atPath(multichainSmartContracts, ":" + deployer.network_id);
17+
const matchingPoolFwdAddr = getSmartContractAddress(chainSmartContracts, ":matching-pool-fwd");
18+
19+
console.log(`Matching Pool Addr: ${matchingPoolFwdAddr}. Chain: ${deployer.network_id}`);
20+
21+
const matchingPoolFwd = await MatchingPool.at(matchingPoolFwdAddr);
22+
23+
for (const admin of parameters.admins) {
24+
console.log ("Adding admin: " + admin);
25+
await matchingPoolFwd.addAdmin(admin, Object.assign(opts, {gas: 5000000}));
26+
}
27+
}

migrations/_99_update_streamtide.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const {readSmartContractsFile, getSmartContractAddress, setSmartContractAddress,
77
const StreamtideForwarder = artifacts.require("MutableForwarder");
88
const Streamtide = artifacts.require("MVPCLR");
99

10-
const smartContracts = readSmartContractsFile(smart_contracts_path);
10+
const [smartContracts, multichainSmartContracts] = readSmartContractsFile(smart_contracts_path);
1111
const streamtideFwdAddr = getSmartContractAddress(smartContracts, ":streamtide-fwd");
1212

1313

@@ -39,7 +39,7 @@ module.exports = async(deployer, network, accounts) => {
3939

4040
setSmartContractAddress(smartContracts, ":streamtide", status.getValue(sk.streamtideAddr));
4141

42-
writeSmartContracts(smart_contracts_path, smartContracts, env);
42+
writeSmartContracts(smart_contracts_path, smartContracts, multichainSmartContracts, env);
4343

4444
status.clean();
4545
console.log ("Done");

0 commit comments

Comments
 (0)