Skip to content

Commit 2012d6f

Browse files
committed
add base sybil contract & sybil provider simulator
1 parent d12c310 commit 2012d6f

File tree

20 files changed

+1114
-1
lines changed

20 files changed

+1114
-1
lines changed

contracts/Cargo.lock

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
[workspace]
2-
members = ["donation", "pot", "pot_deployer", "registry"]
2+
members = [
3+
"donation",
4+
"pot",
5+
"pot_deployer",
6+
"registry",
7+
"sybil",
8+
"sybil_provider_simulator"
9+
]

contracts/package.json

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"build:pot": "cd pot && ./scripts/build.sh && cd ..",
1212
"build:potdeployer": "cd pot_deployer && ./scripts/build.sh && cd ..",
1313
"build:registry": "cd registry && ./scripts/build.sh && cd ..",
14+
"build:sybil": "cd sybil && ./scripts/build.sh && cd ..",
15+
"build:sybilprovider": "cd sybil_provider_simulator && ./scripts/build.sh && cd ..",
1416
"dev:deploy:donation": "cd donation && ./scripts/deploy.sh && cd .. && yarn patch:config donation",
1517
"dev:deploy:donation:refresh": "cd donation && rm -rf neardev && ./scripts/deploy.sh && cd .. && yarn patch:config donation",
1618
"test:donation": "yarn test test/donation/contract.test.ts",
@@ -32,6 +34,11 @@
3234
"test:registry": "yarn test test/registry/contract.test.ts",
3335
"works:registry": "yarn build:registry && yarn dev:deploy:registry && yarn test:registry",
3436
"works:registry:refresh": "yarn build:registry && yarn dev:deploy:registry:refresh && yarn test:registry",
37+
"dev:deploy:sybil": "cd sybil && ./scripts/deploy.sh && cd .. && yarn patch:config sybil",
38+
"dev:deploy:sybil:refresh": "cd sybil && rm -rf neardev && ./scripts/deploy.sh && cd .. && yarn patch:config sybil",
39+
"test:sybil": "yarn test test/sybil/contract.test.ts",
40+
"works:sybil": "yarn build:sybil && yarn dev:deploy:sybil && yarn test:sybil",
41+
"works:sybil:refresh": "yarn build:sybil && yarn dev:deploy:sybil:refresh && yarn test:sybil",
3542
"test": "mocha --require ts-node/register --timeout 240000",
3643
"test:all": "yarn test test/**/contract.test.ts"
3744
},

contracts/sybil/Cargo.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "sybil"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib", "rlib"]
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
[dependencies]
11+
near-sdk = "4.1.1"
12+
13+
[profile.release]
14+
codegen-units = 1
15+
# Tell `rustc` to optimize for small code size.
16+
opt-level = "z"
17+
lto = true
18+
debug = false
19+
panic = "abort"
20+
# Opt into extra safety checks on arithmetic operations https://stackoverflow.com/a/64136471/249801
21+
overflow-checks = true

contracts/sybil/README.md

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# PotLock Donation Contract
2+
3+
## Purpose
4+
5+
Provide a way to donate NEAR or FTs to any account, with a protocol fee taken out
6+
7+
## Contract Structure
8+
9+
### General Types
10+
11+
```rs
12+
type DonationId = u64;
13+
type TimestampMs = u64;
14+
```
15+
16+
### Contract
17+
18+
```rs
19+
pub struct Contract {
20+
contract_source_metadata: LazyOption<VersionedContractSourceMetadata>,
21+
owner: AccountId,
22+
protocol_fee_basis_points: u32,
23+
referral_fee_basis_points: u32,
24+
protocol_fee_recipient_account: AccountId,
25+
donations_by_id: UnorderedMap<DonationId, VersionedDonation>,
26+
donation_ids_by_recipient_id: LookupMap<AccountId, UnorderedSet<DonationId>>,
27+
donation_ids_by_donor_id: LookupMap<AccountId, UnorderedSet<DonationId>>,
28+
donation_ids_by_ft_id: LookupMap<AccountId, UnorderedSet<DonationId>>,
29+
}
30+
31+
/// NOT stored in contract storage; only used for get_config response
32+
pub struct Config {
33+
pub owner: AccountId,
34+
pub protocol_fee_basis_points: u32,
35+
pub referral_fee_basis_points: u32,
36+
pub protocol_fee_recipient_account: AccountId,
37+
}
38+
```
39+
40+
### Donations
41+
42+
_NB: Projects are automatically approved by default._
43+
44+
```rs
45+
pub struct Donation {
46+
/// Unique identifier for the donation
47+
pub id: DonationId,
48+
/// ID of the donor
49+
pub donor_id: AccountId,
50+
/// Amount donated
51+
pub total_amount: U128,
52+
/// FT id (e.g. "near")
53+
pub ft_id: AccountId,
54+
/// Optional message from the donor
55+
pub message: Option<String>,
56+
/// Timestamp when the donation was made
57+
pub donated_at_ms: TimestampMs,
58+
/// ID of the account receiving the donation
59+
pub recipient_id: AccountId,
60+
/// Protocol fee
61+
pub protocol_fee: U128,
62+
/// Referrer ID
63+
pub referrer_id: Option<AccountId>,
64+
/// Referrer fee
65+
pub referrer_fee: Option<U128>,
66+
}
67+
```
68+
69+
### Contract Source Metadata
70+
71+
_NB: Below implemented as per NEP 0330 (https://github.com/near/NEPs/blob/master/neps/nep-0330.md), with addition of `commit_hash`_
72+
73+
```rs
74+
pub struct ContractSourceMetadata {
75+
/// Version of source code, e.g. "v1.0.0", could correspond to Git tag
76+
pub version: String,
77+
/// Git commit hash of currently deployed contract code
78+
pub commit_hash: String,
79+
/// GitHub repo url for currently deployed contract code
80+
pub link: String,
81+
}
82+
```
83+
84+
## Methods
85+
86+
### Write Methods
87+
88+
```rs
89+
// DONATIONS
90+
91+
#[payable]
92+
pub fn donate(
93+
&mut self,
94+
recipient_id: AccountId,
95+
message: Option<String>,
96+
referrer_id: Option<AccountId>,
97+
) -> Donation
98+
99+
// OWNER
100+
101+
#[payable]
102+
pub fn owner_change_owner(&mut self, owner: AccountId)
103+
104+
pub fn owner_set_protocol_fee_basis_points(&mut self, protocol_fee_basis_points: u32)
105+
106+
pub fn owner_set_referral_fee_basis_points(&mut self, referral_fee_basis_points: u32)
107+
108+
pub fn owner_set_protocol_fee_recipient_account(&mut self, protocol_fee_recipient_account: AccountId)
109+
110+
// SOURCE METADATA
111+
112+
pub fn self_set_source_metadata(&mut self, source_metadata: ContractSourceMetadata) // only callable by the contract account (reasoning is that this should be able to be updated by the same account that can deploy code to the account)
113+
114+
```
115+
116+
### Read Methods
117+
118+
```rs
119+
// CONFIG
120+
121+
pub fn get_config(&self) -> Config
122+
123+
// DONATIONS
124+
pub fn get_donations(&self, from_index: Option<u128>, limit: Option<u64>) -> Vec<Donation>
125+
126+
pub fn get_donation_by_id(&self, donation_id: DonationId) -> Option<Donation>
127+
128+
pub fn get_donations_for_recipient(
129+
&self,
130+
recipient_id: AccountId,
131+
from_index: Option<u128>,
132+
limit: Option<u64>,
133+
) -> Vec<Donation>
134+
135+
pub fn get_donations_for_donor(
136+
&self,
137+
donor_id: AccountId,
138+
from_index: Option<u128>,
139+
limit: Option<u64>,
140+
) -> Vec<Donation>
141+
142+
pub fn get_donations_for_ft(
143+
&self,
144+
ft_id: AccountId,
145+
from_index: Option<u128>,
146+
limit: Option<u64>,
147+
) -> Vec<Donation>
148+
149+
// OWNER
150+
151+
pub fn get_owner(&self) -> AccountId
152+
153+
// SOURCE METADATA
154+
155+
pub fn get_contract_source_metadata(&self) -> Option<ContractSourceMetadata>
156+
```
157+
158+
## Events
159+
160+
### `donation`
161+
162+
Indicates that a `Donation` object has been created.
163+
164+
**Example:**
165+
166+
```json
167+
{
168+
"standard": "potlock",
169+
"version": "1.0.0",
170+
"event": "donation",
171+
"data": [
172+
{
173+
"donation": {
174+
"donated_at_ms": 1698948121940,
175+
"donor_id":"lachlan.near",
176+
"ft_id":"near",
177+
"id":9,
178+
"message": "Go go go!",
179+
"protocol_fee": "7000000000000000000000",
180+
"recipient_id": "magicbuild.near",
181+
"referrer_fee": "2000000000000000000000",
182+
"referrer_id": "plugrel.near",
183+
"total_amount": "100000000000000000000000"
184+
},
185+
}
186+
]
187+
}
188+
```
189+
190+
### `set_source_metadata`
191+
192+
Indicates that `ContractSourceMetadata` object has been set/updated.
193+
194+
**Example:**
195+
196+
```json
197+
{
198+
"standard": "potlock",
199+
"version": "1.0.0",
200+
"event": "set_source_metadata",
201+
"data": [
202+
{
203+
"source_metadata": {
204+
"commit_hash":"ec02294253b22c2d4c50a75331df23ada9eb04db",
205+
"link":"https://github.com/PotLock/core",
206+
"version":"0.1.0",
207+
}
208+
}
209+
]
210+
}
211+
```

contracts/sybil/out/main.wasm

230 KB
Binary file not shown.

contracts/sybil/scripts/build.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
3+
echo ">> Building Sybil contract"
4+
5+
set -e
6+
7+
export CARGO_TARGET_DIR=target
8+
RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release
9+
mkdir -p ./out
10+
cp target/wasm32-unknown-unknown/release/*.wasm ./out/main.wasm
11+
echo ">> Finished Building Sybil contract"

contracts/sybil/scripts/deploy.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
3+
if [ $? -ne 0 ]; then
4+
echo ">> Error building Sybil contract"
5+
exit 1
6+
fi
7+
8+
echo ">> Deploying Sybil contract!"
9+
10+
# https://docs.near.org/tools/near-cli#near-dev-deploy
11+
near dev-deploy --wasmFile ./out/main.wasm

contracts/sybil/src/events.rs

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::*;
2+
3+
/// source metadata update
4+
pub(crate) fn log_set_source_metadata_event(source_metadata: &ContractSourceMetadata) {
5+
env::log_str(
6+
format!(
7+
"{}{}",
8+
EVENT_JSON_PREFIX,
9+
json!({
10+
"standard": "potlock",
11+
"version": "1.0.0",
12+
"event": "set_source_metadata",
13+
"data": [
14+
{
15+
"source_metadata": source_metadata,
16+
}
17+
]
18+
})
19+
)
20+
.as_ref(),
21+
);
22+
}
23+
24+
/// add provider
25+
pub(crate) fn log_add_provider_event(provider_id: &ProviderId, provider: &Provider) {
26+
env::log_str(
27+
format!(
28+
"{}{}",
29+
EVENT_JSON_PREFIX,
30+
json!({
31+
"standard": "potlock",
32+
"version": "1.0.0",
33+
"event": "add_provider",
34+
"data": [
35+
{
36+
"provider_id": provider_id,
37+
"provider": provider,
38+
}
39+
]
40+
})
41+
)
42+
.as_ref(),
43+
);
44+
}

contracts/sybil/src/internal.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use crate::*;
2+
3+
impl Contract {
4+
pub(crate) fn is_owner(&self) -> bool {
5+
env::predecessor_account_id() == self.owner
6+
}
7+
8+
pub(crate) fn is_admin(&self) -> bool {
9+
self.admins.contains(&env::predecessor_account_id())
10+
}
11+
12+
pub(crate) fn is_owner_or_admin(&self) -> bool {
13+
self.is_owner() || self.is_admin()
14+
}
15+
16+
pub(crate) fn assert_owner(&self) {
17+
assert!(self.is_owner(), "Only contract owner can call this method");
18+
}
19+
20+
pub(crate) fn assert_admin(&self) {
21+
assert!(self.is_admin(), "Only contract admin can call this method");
22+
}
23+
24+
pub(crate) fn assert_owner_or_admin(&self) {
25+
assert!(
26+
self.is_owner_or_admin(),
27+
"Only contract owner or admin can call this method"
28+
);
29+
}
30+
}

0 commit comments

Comments
 (0)