Skip to content

Commit 4d9e48d

Browse files
committed
slightly better error reporting
1 parent f8aac06 commit 4d9e48d

File tree

3 files changed

+53
-16
lines changed

3 files changed

+53
-16
lines changed

Home.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,8 @@ def display_passport_usage(data):
535535
hide_index=True
536536
)
537537

538-
def calculate_matching_results(data):
539-
"""Calculate matching results using different strategies (COCM, QF, and TQF)."""
538+
539+
def get_donation_matrix(data):
540540
# Apply voting eligibility based on passport scores and donation thresholds
541541
df_with_passport = fundingutils.apply_voting_eligibility(
542542
data['df'].copy(),
@@ -546,6 +546,12 @@ def calculate_matching_results(data):
546546
data['scaling_df']
547547
)
548548
donation_matrix = fundingutils.pivot_votes(df_with_passport)
549+
return donation_matrix
550+
551+
def calculate_matching_results(data):
552+
"""Calculate matching results using different strategies (COCM, QF, and TQF)."""
553+
554+
donation_matrix = data['donation_matrix']
549555

550556
#donation_matrix.to_csv('name me'.csv')
551557

@@ -557,15 +563,15 @@ def calculate_matching_results(data):
557563
for strategy in [data['strat'], 'QF']]
558564

559565
matching_dfs.append(fundingutils.tunable_qf(
560-
df_with_passport,
566+
donation_matrix,
561567
data['token_distribution_df'],
562568
'TQF',
563569
matching_cap_amount,
564570
matching_amount,
565571
))
566572

567573
matching_dfs.append(fundingutils.tunable_qf(
568-
df_with_passport,
574+
donation_matrix,
569575
data['token_distribution_df'],
570576
data['strat'],
571577
matching_cap_amount,
@@ -588,7 +594,7 @@ def calculate_matching_results(data):
588594
matching_df['Δ TQF'] = matching_df['matching_amount_TQF'] - matching_df['matching_amount_QF']
589595
matching_df['Δ TQF_COCM'] = matching_df['matching_amount_TQF_COCM'] - matching_df['matching_amount_TQF']
590596

591-
return matching_df.sort_values(f'matching_amount_{data["suffix"]}', ascending=False), donation_matrix
597+
return matching_df.sort_values(f'matching_amount_{data["suffix"]}', ascending=False)
592598

593599
def display_matching_results(matching_df, matching_token_symbol, s, using_TQF):
594600
"""Display the matching results in a formatted table."""
@@ -1086,6 +1092,31 @@ def main():
10861092
# Passport usage section (ONLY APPEARS IF SYBIL DEFENSE IS ENABLED)
10871093
display_passport_usage(data)
10881094

1095+
1096+
1097+
### get donation matrix (post passport)
1098+
donation_matrix = get_donation_matrix(data)
1099+
1100+
data['donation_matrix'] = donation_matrix
1101+
1102+
g_idx = {w: fundingutils.gini(list(donation_matrix.loc[w])) for w in donation_matrix.index if sum(donation_matrix.loc[w]) > 0}
1103+
passing_donors = g_idx.keys()
1104+
num_passing_donors = len(passing_donors)
1105+
1106+
st.header('👥 Donation Inequality')
1107+
st.write('''COCM can be gamed when individuals make highly unequal donations to different projects.''')
1108+
st.write('''We can measure inequality in someone's donation via a tool called the [Gini Index](https://en.wikipedia.org/wiki/Gini_coefficient). An index of 0 means the donations are very even across projects. An index of 1 means the donations are highly uneven across projects.''')
1109+
st.write('''In this section, you can remove donors with highly unequal donation profiles.''')
1110+
gini_cutoff = st.slider('Select Inequality Cutoff:', min_value = 0.0, max_value = 1.0, value=1.0, step = 0.02)
1111+
1112+
removed_donors = [w for w in passing_donors if g_idx[w] > gini_cutoff]
1113+
num_removed_donors = len(removed_donors)
1114+
st.write(f'A cutoff of {gini_cutoff} will remove {num_removed_donors} out of {num_passing_donors} otherwise eligible donors ({round(num_removed_donors/num_passing_donors * 100)} \%)')
1115+
1116+
1117+
### calculate matching results ###
1118+
matching_df = calculate_matching_results(data)
1119+
10891120
# Quadratic Funding Method Comparison section
10901121
st.header('💚 Quadratic Funding Method Comparison')
10911122
st.write('''[Quadratic funding](https://wtfisqf.com) helps us solve coordination failures by creating a way for community members to fund what matters to them while amplifying their impact. However, its assumption that people make independent decisions can be exploited to unfairly influence the distribution of matching funds.''')
@@ -1096,10 +1127,9 @@ def main():
10961127
data['projects_to_remove'] = st.multiselect('Projects may be removed from the matching distribution by selecting them here:', all_projects)
10971128
data['df'] = data['df'][~data['df']['project_name'].isin(data['projects_to_remove'])]
10981129

1099-
# Calculate and display matching results
1100-
matching_df, donation_matrix = calculate_matching_results(data)
1130+
11011131
display_matching_results(matching_df, data['config_df']['token_code'].iloc[0], data['suffix'], data['using TQF'])
1102-
display_singledonor_and_alldonor_stats(donation_matrix)
1132+
display_singledonor_and_alldonor_stats(data['donation_matrix'])
11031133
display_network_graph(data['df'])
11041134

11051135

fundingutils.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,11 @@ def tunable_qf(donation_df, token_distribution_df,algo, matching_cap_percent, ma
394394
Calculate quadratic funding with optional boost factors for donors.
395395
396396
Args:
397-
donation_df: DataFrame with voter donations
397+
donation_df: matrix of voter donations
398398
token_distribution_df: DataFrame with [address, scale_factor] columns
399399
matching_cap_percent: Maximum percentage for matching
400400
matching_amount: Total matching pool size
401401
"""
402-
# Create votes matrix
403-
votes_df = pivot_votes(donation_df)
404402

405403
# Apply scale factors if provided
406404
if token_distribution_df is not None:
@@ -410,11 +408,20 @@ def tunable_qf(donation_df, token_distribution_df,algo, matching_cap_percent, ma
410408
token_distribution_df.index = token_distribution_df.index.str.lower()
411409

412410
# Apply scale factors to each voter's donations
413-
for voter in votes_df.index:
411+
for voter in donation_df.index:
414412
voter_lower = voter.lower()
415413
if voter_lower in token_distribution_df.index:
416414
scale = token_distribution_df.loc[voter_lower, 'scale_factor']
417-
votes_df.loc[voter] *= scale
415+
donation_df.loc[voter] *= scale
418416

419417
# Calculate QF with scaled votes
420-
return get_qf_matching(algo, votes_df, matching_cap_percent, matching_amount, cluster_df, pct_cocm)
418+
return get_qf_matching(algo, donation_df, matching_cap_percent, matching_amount, cluster_df, pct_cocm)
419+
420+
421+
def gini(l, on_gt_0 = True):
422+
if on_gt_0:
423+
l2 = [x for x in l if x > 0]
424+
l = l2
425+
num = sum(abs(i - j) for i in l for j in l)
426+
denom = 2 * len(l) * sum(l)
427+
return num / denom

utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def fetch_tokens_config():
173173
response = requests.get(url)
174174
response.raise_for_status() # Raise an error for bad responses
175175
except requests.RequestException as e:
176-
print(f"Failed to fetch data from {url}. Error: {e}")
176+
st.write(f"Failed to fetch data from {url}. Error: {e}")
177177
return None
178178

179179
df = parse_config_file(response.text)
@@ -249,4 +249,4 @@ def fetch_latest_price(chain_id, token_address, coingecko_api_key=st.secrets['co
249249
if key not in response_data:
250250
raise ValueError(f"Token {'native' if is_native_token else 'address'} '{key}' not found in the response data.")
251251

252-
return response_data[key]["usd"]
252+
return response_data[key]["usd"]

0 commit comments

Comments
 (0)