Skip to content

Commit 7bca88b

Browse files
authored
Merge pull request #4 from 0xSpaceShard/fix/refacto-and-loop
refacto: Add getter in factory for pooling manager and make all contr…
2 parents 76511eb + 453b7c7 commit 7bca88b

24 files changed

Lines changed: 5112 additions & 748 deletions

README.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
## Yield Dex
2+
3+
L2 contracts for Yield Dex project.
4+
5+
### Compilation
6+
7+
We are using Scarb to compile our contracts, you need to install it to be able to use it.
8+
For that, you can follow the steps [here](https://book.cairo-lang.org/ch01-01-installation.html).
9+
Once Scarb is installed, you are able to compile the contracts.
10+
Run `scarb build`, it will build Sierra code of this package which will be written to the `target/dev` directory.
11+
12+
### Test
13+
14+
You can find our tests under `src/tests`, these tests are written using snfoundry you can find more information [here](https://foundry-rs.github.io/starknet-foundry/getting-started/installation.html).
15+
Follow the installation documentation to be able to run our tests.
16+
To run the tests, just do `snforge test`.
17+
18+
### Declare With Starkli
19+
20+
For this, we used starkli, you need to install it to be able to declare and deploy the contracts.
21+
Once starkli is installed, you will need to set some environment variables.
22+
If you want to declare on goerli then do `export STARKNET_NETWORK="goerli"` (you replace it be mainnet or sepolia depending on the network you want to deploy to).
23+
You will have to create a signers and account, just follow those [documentation](https://book.starkli.rs/signers).
24+
Now that everything is set up, you are able to declare the contracts.
25+
For that, we will use starkli declare command, for more info check the documentation [here](https://book.starkli.rs/declaring-classes).
26+
Run `starkli declare ./target/dev/CONTRACT_NAME.contract_class.json --account PATH/account-store --network NETWORK`.
27+
`CONTRACT_NAME `the name of the json file that can be found inside `./target/dev/ `folder.
28+
`PATH/account-store` is the path to your account-store that has been previously created.
29+
`NETWORK `the name of the network you want to declare to (goerli, sepolia or mainnet).
30+
After running that, it will return to you the declared contract class hash.
31+
32+
### Declare With Script
33+
34+
Create a `.env` and add `ACCOUNT_ADDRESS` and `ACCOUNT_PK`.
35+
Run `npm i` to install the package.
36+
The script is deploying the contract on goerli if you want to deploy on another network then go inside `scripts/declareContracts` and change `const provider = new RpcProvider({ nodeUrl: constants.NetworkName.SN_MAIN });` with the correct network (ex: SN_GOERLI).
37+
To run the script just do `npx ts-node scripts/declareContracts.ts --contract CONTRACT_NAME.`
38+
`CONTRACT_NAME` must be replaced by :
39+
- PoolingManager
40+
- Factory
41+
- Token
42+
- TokenManager
43+
44+
### Deploy With Starkli
45+
46+
Now that our contracts are declared, the next step is to deploy them. For that, you can follow the documentation [here](https://book.starkli.rs/deploying-contracts).
47+
Some of the contracts take parameters in their constructor, you will need to add them in your command.
48+
49+
PoolingManager: `starkli deploy POOLING_MANAGER_CLASS_HASH OWNER_ACCOUNT_ADDRESS --account PATH/account-store --network NETWORK`
50+
Factory: `starkli deploy FACTORY_CLASS_HASH POOLING_MANAGER_CONTRACT_ADDRESS TOKEN_CLASS_HASH TOKEN_MANAGER_CLASS_HASH --account PATH/account-store --network NETWORK`
51+
52+
### Deploy With Script
53+
54+
Create a `.env` and add `ACCOUNT_ADDRESS` and `ACCOUNT_PK`.
55+
Run `npm i` to install the package.
56+
The script is deploying the contract on goerli if you want to deploy on another network then go inside `scripts/deployContracts` and change `const provider = new RpcProvider({ nodeUrl: constants.NetworkName.SN_MAIN });` with the correct network (ex: `SN_GOERLI`).
57+
To run the script just do `npx ts-node scripts/deployContracts.ts --contract CONTRACT_NAME`.
58+
`CONTRACT_NAME` must be replaced by :
59+
- PoolingManager
60+
- Factory
61+
62+
### Setup
63+
Only the owner of the contract will be able to set up the contract.
64+
You can do the setup through voyager or starkscan.
65+
66+
PoolingManager:
67+
Only Owner:
68+
- set_fees_recipient: Address of the fees recipient.
69+
- set_l1_pooling_manager: Address of the pooling manager on l1.
70+
- set_factory: Address of the Factory contract previously deployed.
71+
72+
Only Role, the owner has the correct role, but you can also give permission to other accounts:
73+
- register_underlying: Registers an underlying asset, its corresponding bridge contract and the corresponding address of the l1bridge
74+
75+
Factory:
76+
Only Owner:
77+
- `deploy_strategy`: Deploys a new strategy with specified parameters.
78+
Parameters are:
79+
- l1_strategy: The Ethereum address of the L1 strategy
80+
- underlying: The contract address of the underlying asset
81+
- token_name: The name for the new token
82+
- token_symbol: The symbol for the new token
83+
- performance_fees: The performance fees for the strategy
84+
- min_deposit: The minimum deposit limit
85+
- max_deposit: The maximum deposit limit
86+
- min_withdrawal: The minimum withdrawal limit
87+
- max_withdrawal: The maximum withdrawal limit
88+
- withdrawal_epoch_delay: The delay in epochs for withdrawals
89+
- dust_limit: The dust limit for the strategy
90+
Deploy_strategy will deploy a new contract called token_manager and return you the address. We are going to use this contract to deposit some tokens.
91+
92+
Go to the Token Manager contract address and call the deposit function, This function can be called by any user :
93+
94+
TokenManager:
95+
- `deposit`: Allows a user to deposit assets into the contract.
96+
Parameters are:
97+
- assets: The amount of assets to deposit.
98+
- receiver: The address to receive the minted shares.
99+
- referral: The referral address for the deposit.
100+
Once users have deposited some assets, they can now request a withdrawal from the contract.
101+
- `request_withdrawal`: Allows a user to request a withdrawal from the contract
102+
Parameter is:
103+
- shares: The amount of shares to withdraw.
104+
105+
### Goerli Class Hash
106+
You can declare a contract only once on each network. So if you don't do any modification into our current contract implementation you may face an error while declaring. Therefore here you can find the current class hash of each contract on Goerli.
107+
108+
```
109+
POOLINGMANAGER_CLASS_HASH="0x05adb7661d0dcb3cc5fbe69380846fb7662c92f1943fcf609c51b756cae7d411"
110+
111+
TOKENMANAGER_CLASS_HASH="0x03be98338455134abae1d830802a162cd81b24ddb38a868ec9c6a4341ecd7210"
112+
113+
TOKENMOCK_CLASS_HASH="0x00da57dbb24ceb46a3901f148442e0d591528baba485ee84ed6d4948dedf12e5"
114+
115+
TOKEN_CLASS_HASH="0x0720f601c0432ab03e12df99c2b215e7ab9a9c12e1b4d8b0473e18bbb3213bea"
116+
117+
TOKENBRIDGE_CLASS_HASH="0x00de6d9bd84775dd221273e833dc44946da586483cf822e0021385de95964700"
118+
119+
FACTORY_CLASS_HASH="0x0581277daf0e409c2537979108b7eb4a5cec3624db552c35f8f6acc9a3ac937b"
120+
```
121+
122+
123+
### Mainnet Class Hash
124+
You can declare a contract only once on each network. So if you don't do any modification into our current contract implementation you may face an error while declaring. Therefore here you can find the current class hash of each contract on Mainnet.
125+
126+
```
127+
POOLINGMANAGER_CLASS_HASH=0x05adb7661d0dcb3cc5fbe69380846fb7662c92f1943fcf609c51b756cae7d411
128+
129+
FACTORY_CLASS_HASH=0x581277daf0e409c2537979108b7eb4a5cec3624db552c35f8f6acc9a3ac937b
130+
131+
TOKENMANAGER_CLASS_HASH=0x3be98338455134abae1d830802a162cd81b24ddb38a868ec9c6a4341ecd7210
132+
133+
TOKEN_CLASS_HASH=0x720f601c0432ab03e12df99c2b215e7ab9a9c12e1b4d8b0473e18bbb3213bea
134+
```
135+
136+

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"dependencies": {
3+
"dotenv": "^16.3.1",
4+
"fs": "^0.0.1-security",
5+
"starknet": "^5.24.3"
6+
},
7+
"devDependencies": {
8+
"@types/node": "^20.11.5"
9+
}
10+
}

scripts/declareContracts.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Account, Provider, Contract, json, RpcProvider, constants } from 'starknet';
2+
import fs from 'fs';
3+
import dotenv from 'dotenv';
4+
5+
dotenv.config({ path: __dirname + '/../.env' });
6+
7+
const provider = new RpcProvider({ nodeUrl: constants.NetworkName.SN_MAIN });
8+
9+
const owner = new Account(provider, process.env.ACCOUNT_ADDRESS as string, process.env.ACCOUNT_PK as string, "1");
10+
11+
export async function declareContract(name: string) {
12+
const compiledContract = await json.parse(fs.readFileSync(`./target/dev/nimbora_yields_${name}.contract_class.json`).toString('ascii'));
13+
const compiledSierraCasm = await json.parse(fs.readFileSync(`./target/dev/nimbora_yields_${name}.compiled_contract_class.json`).toString('ascii'));
14+
const declareResponse = await owner.declare({
15+
contract: compiledContract,
16+
casm: compiledSierraCasm,
17+
});
18+
19+
console.log('Contract classHash: ', declareResponse.class_hash);
20+
fs.appendFile(__dirname + '/../.env', `\n${name.toUpperCase()}_CLASS_HASH=${declareResponse.class_hash}`, function (err) {
21+
if (err) throw err;
22+
});
23+
}
24+
25+
async function main() {
26+
if (!process.argv[2] || !process.argv[3]) {
27+
throw new Error("Missing --contract <contract_name>");
28+
}
29+
30+
switch (process.argv[3]) {
31+
case "PoolingManager":
32+
console.log("Declaring PoolingManager...");
33+
await declareContract('PoolingManager');
34+
35+
break;
36+
37+
case "Factory":
38+
console.log("Declaring Factory...");
39+
await declareContract('Factory');
40+
41+
break;
42+
43+
case "TokenManager":
44+
console.log("Declaring TokenManager...");
45+
await declareContract('TokenManager');
46+
47+
break;
48+
49+
case "Token":
50+
console.log("Declaring Token...");
51+
await declareContract('Token');
52+
53+
break;
54+
55+
default:
56+
throw new Error("Error: Unknown contract");
57+
}
58+
}
59+
60+
main();

scripts/deployContracts.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { Account, Provider, Contract, json, uint256, RpcProvider, constants } from "starknet";
2+
import fs from 'fs';
3+
import dotenv from 'dotenv';
4+
import { appendToEnv } from "./utils";
5+
6+
dotenv.config({ path: __dirname + '/../.env' })
7+
8+
const provider = new RpcProvider({ nodeUrl: constants.NetworkName.SN_MAIN });
9+
const owner = new Account(provider, process.env.ACCOUNT_ADDRESS as string, process.env.ACCOUNT_PK as string, "1");
10+
11+
async function deployPoolingManagerContract(): Promise<Contract> {
12+
let contractAddress: any;
13+
const compiledContract = await json.parse(fs.readFileSync(`./target/dev/nimbora_yields_PoolingManager.contract_class.json`).toString('ascii'));
14+
15+
let { transaction_hash, contract_address } = await owner.deploy({
16+
classHash: process.env.POOLINGMANAGER_CLASS_HASH as string,
17+
constructorCalldata: {
18+
owner: owner.address,
19+
},
20+
});
21+
[contractAddress] = contract_address;
22+
// await provider.waitForTransaction(transaction_hash);
23+
24+
const poolingManagerContract = new Contract(compiledContract.abi, contractAddress, owner);
25+
console.log('✅ Test PoolingManager contract connected at =', poolingManagerContract.address);
26+
27+
return poolingManagerContract;
28+
}
29+
30+
async function deployFactoryContract(): Promise<Contract> {
31+
let contractAddress: any;
32+
const compiledContract = await json.parse(fs.readFileSync(`./target/dev/nimbora_yields_Factory.contract_class.json`).toString('ascii'));
33+
34+
let { transaction_hash, contract_address } = await owner.deploy({
35+
classHash: process.env.FACTORY_CLASS_HASH as string,
36+
constructorCalldata: {
37+
pooling_manager: process.env.POOLINGMANAGER_ADDRESS as string,
38+
token_class_hash: process.env.TOKEN_CLASS_HASH as string,
39+
token_manager_class_hash: process.env.TOKENMANAGER_CLASS_HASH as string,
40+
},
41+
});
42+
[contractAddress] = contract_address;
43+
// await provider.waitForTransaction(transaction_hash);
44+
45+
const factoryContract = new Contract(compiledContract.abi, contractAddress, owner);
46+
console.log('✅ Test Factory contract connected at =', factoryContract.address);
47+
48+
return factoryContract;
49+
}
50+
51+
52+
53+
54+
async function main() {
55+
56+
const flag = process.argv[2];
57+
const action = process.argv[3];
58+
59+
if (!flag || !action) {
60+
throw new Error("Missing --contract <contract_name>");
61+
}
62+
63+
if (flag == "--contract") {
64+
switch (action) {
65+
case "PoolingManager":
66+
console.log("Deploying PoolingManager...");
67+
68+
const poolingManagerContract = await deployPoolingManagerContract(
69+
);
70+
break;
71+
72+
case "Factory":
73+
console.log("Deploying Factory...");
74+
const factoryContractAddress = await deployFactoryContract();
75+
76+
break;
77+
}
78+
} else if (flag == "--setup") {
79+
const contract_address = process.argv[4];
80+
if (!contract_address) {
81+
throw new Error("Error: Provide contract address");
82+
}
83+
}
84+
}
85+
86+
main();

scripts/utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import fs from 'fs';
2+
import dotenv from 'dotenv';
3+
4+
dotenv.config({ path: __dirname + '/../.env' })
5+
6+
export async function appendToEnv(name: string, address: string) {
7+
fs.appendFile(`${__dirname}/../.env`, `\n${name}_ADDRESS=${address}`, function (
8+
err,
9+
) {
10+
if (err) throw err
11+
})
12+
}

src/factory/factory.cairo

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod Factory {
1717
IAccessControlDispatcher, IAccessControlDispatcherTrait
1818
};
1919
use openzeppelin::token::erc20::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait};
20+
use openzeppelin::upgrades::UpgradeableComponent;
2021

2122

2223
// Local imports.
@@ -25,8 +26,15 @@ mod Factory {
2526
IPoolingManagerDispatcher, IPoolingManagerDispatcherTrait
2627
};
2728

29+
// Components
30+
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);
31+
32+
impl InternalUpgradeableImpl = UpgradeableComponent::InternalImpl<ContractState>;
33+
2834
#[storage]
2935
struct Storage {
36+
#[substorage(v0)]
37+
upgradeable: UpgradeableComponent::Storage,
3038
pooling_manager: ContractAddress,
3139
token_class_hash: ClassHash,
3240
token_manager_class_hash: ClassHash
@@ -36,6 +44,8 @@ mod Factory {
3644
#[event]
3745
#[derive(Drop, starknet::Event)]
3846
enum Event {
47+
#[flat]
48+
UpgradeableEvent: UpgradeableComponent::Event,
3949
TokenHashUpdated: TokenHashUpdated,
4050
TokenManagerHashUpdated: TokenManagerHashUpdated
4151
}
@@ -76,6 +86,13 @@ mod Factory {
7686
self._set_token_manager_class_hash(token_manager_class_hash);
7787
}
7888

89+
/// @notice Upgrade contract
90+
/// @param New contract class hash
91+
#[external(v0)]
92+
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
93+
self._assert_only_owner();
94+
self.upgradeable._upgrade(new_class_hash);
95+
}
7996

8097
#[abi(embed_v0)]
8198
impl Factory of IFactory<ContractState> {
@@ -91,6 +108,12 @@ mod Factory {
91108
self.token_class_hash.read()
92109
}
93110

111+
/// @notice Reads the pooling manager contract address
112+
/// @return The address of the pooling manager
113+
fn pooling_manager_address(self: @ContractState) -> ContractAddress {
114+
self.pooling_manager.read()
115+
}
116+
94117
/// @notice Deploys a new strategy with specified parameters
95118
/// @dev Only callable by the owner of the contract
96119
/// @param l1_strategy The Ethereum address of the L1 strategy

src/factory/interface.cairo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use starknet::{ContractAddress, ClassHash, eth_address::EthAddress};
44
trait IFactory<TContractState> {
55
fn token_manager_class_hash(self: @TContractState) -> ClassHash;
66
fn token_class_hash(self: @TContractState) -> ClassHash;
7+
fn pooling_manager_address(self: @TContractState) -> ContractAddress;
78

89
fn deploy_strategy(
910
ref self: TContractState,

src/lib.cairo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ mod pooling_manager;
44
mod token_manager;
55
mod factory;
66
mod token_bridge;
7+
mod mocks;
78
#[cfg(test)]
89
mod tests;

src/mocks.cairo

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod mock_pooling_manager;
2+
mod mock_factory;
3+
mod mock_token_manager;

0 commit comments

Comments
 (0)