Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
63a85f0
add approved projects from review
Prometheo May 27, 2025
15ba094
remove payout address from grantpicks
Prometheo May 28, 2025
a9c6922
add approved application to projects
Prometheo May 28, 2025
02a3383
use project owner account instance
Prometheo May 28, 2025
82c81c5
add minimum_deposit
Prometheo Jun 2, 2025
44e0e38
change stellar testnet address
Prometheo Jun 18, 2025
20f871e
starting ledger
Prometheo Jun 18, 2025
1a96c3f
change contract:
Prometheo Jul 3, 2025
dfa7c76
change contract address
Prometheo Jul 3, 2025
7bd3ab3
change contract id
Prometheo Jul 8, 2025
a3978d8
upgrade stellar sdk
Prometheo Jul 21, 2025
7ccd5eb
update stellar address
Prometheo Jul 24, 2025
94bf1e8
index campaigns
Prometheo Jul 29, 2025
8b2a160
Merge pull request #171 from PotLock/campaign-indexing
Prometheo Jul 29, 2025
d688f0f
Merge pull request #172 from PotLock/testnet
Prometheo Jul 29, 2025
c7fa558
add script to backfil
Prometheo Jul 31, 2025
bc3ccf5
Merge pull request #173 from PotLock/backfil-script
Prometheo Jul 31, 2025
c5b9d24
Merge pull request #174 from PotLock/testnet
Prometheo Jul 31, 2025
09d4594
feat: implement filters
Prometheo Aug 5, 2025
700a538
Merge pull request #175 from PotLock/testnet
Prometheo Aug 5, 2025
482f8c7
update campaign totals
Prometheo Aug 5, 2025
768e453
campaign id tla
Prometheo Aug 5, 2025
087d462
Merge pull request #176 from PotLock/testnet
Prometheo Aug 5, 2025
6a4907e
add status field
Prometheo Aug 13, 2025
6aaae06
Merge pull request #177 from PotLock/testnet
Prometheo Aug 13, 2025
13a9b9f
stellar update
Prometheo Aug 18, 2025
74c0e35
pick address from env
Prometheo Aug 27, 2025
24a5dfd
Merge pull request #178 from PotLock/testnet
Prometheo Aug 27, 2025
fe97729
change stellar mainnet rpc
Prometheo Aug 27, 2025
bf4c280
Merge pull request #179 from PotLock/testnet
Prometheo Aug 27, 2025
79cc8d8
add asyncio wait for to tackle task execution hanging
Prometheo Aug 31, 2025
ebb7f6a
Merge pull request #180 from PotLock/testnet
Prometheo Aug 31, 2025
3c8bb8a
lax timeout
Prometheo Sep 4, 2025
b24c327
Merge pull request #182 from PotLock/testnet
Prometheo Sep 4, 2025
69a6b37
allow app to dev:
Prometheo Sep 8, 2025
378ea96
Merge pull request #183 from PotLock/testnet
Prometheo Sep 8, 2025
41fdf96
change applications project to actual grantpicks project
Prometheo Sep 16, 2025
e651c61
create application for approved projects by owner
Prometheo Sep 16, 2025
2e193ab
index lists on stellar
Prometheo Sep 23, 2025
5061ac0
add chain to serializer
Prometheo Sep 24, 2025
504efcc
fetch list detail by chain and id
Prometheo Sep 24, 2025
a4ded25
make chain query param for list deets
Prometheo Sep 24, 2025
4a9a375
filter by chain name
Prometheo Sep 24, 2025
b78a6d0
fix susbcription:
Prometheo Sep 26, 2025
707b33f
make video url optional
Prometheo Oct 10, 2025
27cc912
list registration
Prometheo Oct 11, 2025
f2684cf
filter with chain name
Prometheo Oct 11, 2025
18e01d2
fix list update on stellar
Prometheo Oct 13, 2025
7f60e0f
extend cors
Prometheo Oct 14, 2025
5a20bba
extend cors
Prometheo Oct 14, 2025
3f2ba37
fix get or create
Prometheo Oct 22, 2025
8bcab7a
add onchain id to list reg
Prometheo Oct 22, 2025
9f9f2da
replace public address
Prometheo Oct 24, 2025
98e8df1
add list reg update
Prometheo Oct 26, 2025
bc6a349
add model constraint
Prometheo Oct 26, 2025
23a1b02
addd logging
Prometheo Oct 26, 2025
114a7cc
addd logging
Prometheo Oct 26, 2025
0feae39
fix list reg updte
Prometheo Oct 26, 2025
c10ed44
Merge pull request #184 from PotLock/testnet
Prometheo Oct 27, 2025
2fd8090
fix: remove caching
Prometheo Nov 3, 2025
6295826
fix campaign delete
Prometheo Nov 25, 2025
19cbea7
Merge pull request #185 from PotLock/testnet
Prometheo Nov 25, 2025
4ef2ded
Added campaigns sycn API's
aunali8812 Jan 28, 2026
52d67fd
Resolved PR comments
aunali8812 Feb 2, 2026
ae3cf22
Merge pull request #186 from PotLock/feature/sync-campaigns
aunali8812 Feb 3, 2026
be9cedd
Merge pull request #187 from PotLock/testnet
aunali8812 Feb 5, 2026
065f6e8
Merge remote-tracking branch 'origin/dev' into feature/sync-accounts-…
aunali8812 Feb 6, 2026
9bf1618
Added accounts and list sync endpoints
aunali8812 Feb 8, 2026
b9c452a
Merge pull request #188 from PotLock/feature/sync-accounts-lists
aunali8812 Feb 8, 2026
db66701
Fix bug in get lists api
aunali8812 Feb 8, 2026
c2d8990
Add diret donation sync for lists donations
aunali8812 Feb 9, 2026
74921a0
Fixed net amount calculation in direct donation sync
aunali8812 Feb 9, 2026
f80a556
Merge pull request #189 from PotLock/testnet
aunali8812 Feb 9, 2026
9cde009
minor change to trigger deployment
aunali8812 Feb 9, 2026
ada58a8
Added pots sync endpoints
aunali8812 Feb 11, 2026
cf1f05f
Merge pull request #191 from PotLock/feature/sync-pots
aunali8812 Feb 11, 2026
aeeb3e9
Merge pull request #192 from PotLock/feature/sync-pots
aunali8812 Feb 16, 2026
9fac5e0
Added campaign deletion,refund and unescrow sync endpoints
aunali8812 Feb 18, 2026
cd4b50e
Merge pull request #194 from PotLock/feature/campaign-sync-complete
aunali8812 Feb 18, 2026
bca26f1
Merge pull request #195 from PotLock/testnet
aunali8812 Feb 19, 2026
88004f3
Added pots sync endpoints
aunali8812 Feb 11, 2026
2a71801
Added list deletion and upvote/remove upvote sync endpoints
aunali8812 Feb 20, 2026
13e4e01
Merge pull request #197 from PotLock/feature/lists-sync-complete
aunali8812 Feb 22, 2026
7ce5c69
Implemented all grantpicks sync endpoints
aunali8812 Mar 8, 2026
02d36ea
Merge pull request #201 from PotLock/feature/grantpicks-round-applica…
aunali8812 Mar 8, 2026
629360c
Added grantpicks list sync endpoints
aunali8812 Mar 8, 2026
e78e93f
Merge pull request #202 from PotLock/feature/grantpicks-round-applica…
aunali8812 Mar 8, 2026
6d9bcae
Seperated grantpicks endpoints for clarity
aunali8812 Mar 8, 2026
dbe0f0f
Merge pull request #203 from PotLock/feature/grantpicks-sync
aunali8812 Mar 8, 2026
1f50f72
Added 501c3 verification
aunali8812 Mar 25, 2026
922ccec
Merge pull request #207 from PotLock/feature/501c3-verification-dev
aunali8812 Mar 25, 2026
7930c59
Replace ProPublica with local IRS data and monthly update task
aunali8812 Apr 5, 2026
3052abf
Merge pull request #210 from PotLock/feature/local-IRS-population
aunali8812 Apr 5, 2026
38ba006
Add bi-weekly backfill task
aunali8812 Apr 8, 2026
f4261a9
Merge pull request #212 from PotLock/feature/biweekly-backfill
aunali8812 Apr 8, 2026
f24fda1
Made fixes to backfill file
aunali8812 Apr 8, 2026
ec436e4
Merge pull request #213 from PotLock/feature/biweekly-backfill
aunali8812 Apr 8, 2026
a02ef39
Fix backfill script
aunali8812 Apr 12, 2026
3fb8d1a
Merge pull request #214 from PotLock/feature/biweekly-backfill
aunali8812 Apr 12, 2026
9ea7e9d
fix backfill incorecctly touching stellar lists
aunali8812 Apr 12, 2026
5ea40f6
Merge pull request #215 from PotLock/feature/biweekly-backfill
aunali8812 Apr 12, 2026
b4f17ac
Add global daily metrics for POTLOCK
aunali8812 May 25, 2026
06116ee
Merge pull request #218 from PotLock/feature/daily-stats-signal
aunali8812 May 25, 2026
f47b5c5
Add /api/v1/stats/campaigns endpoint
aunali8812 Jun 15, 2026
51d7847
Merge dev into feature/campaign-stats-endpoint
aunali8812 Jun 15, 2026
1533e2d
Merge pull request #220 from PotLock/feature/campaign-stats-endpoint
aunali8812 Jun 15, 2026
e18398e
Compute campaign raised USD on the fly in stats endpoint
aunali8812 Jun 15, 2026
f0760fd
Merge pull request #222 from PotLock/feature/campaign-stats-usd
aunali8812 Jun 15, 2026
62b46d8
Add campaign donation count + USD to campaign-stats endpoint
aunali8812 Jun 16, 2026
80ff6cf
Merge pull request #223 from PotLock/feature/campaign-stats-donations
aunali8812 Jun 16, 2026
f9fb885
Add NEAR amount + approx USD for campaign donations to stats endpoint
aunali8812 Jun 16, 2026
dde3055
Merge pull request #225 from PotLock/fix/campaign-donation-near
aunali8812 Jun 16, 2026
af29782
Fix NEAR campaign donation detection (near token, not null) and avoid…
aunali8812 Jun 16, 2026
468d594
Merge pull request #227 from PotLock/fix/campaign-near-filter
aunali8812 Jun 16, 2026
5b8bbb4
Use CoinGecko live simple-price for NEAR USD approximation in campaig…
aunali8812 Jun 16, 2026
f323c68
Merge pull request #228 from PotLock/fix/near-live-price
aunali8812 Jun 16, 2026
85d110e
Use CoinGecko public no-key endpoint for NEAR price (configured key i…
aunali8812 Jun 16, 2026
2737c72
Merge pull request #229 from PotLock/fix/near-price-public-coingecko
aunali8812 Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ media/
# Celery beat schedule file
celerybeat-schedule
dump.rdb
celerybeat-schedule.db

# Flask stuff:
instance/
Expand Down Expand Up @@ -135,3 +136,5 @@ dmypy.json
# static

/static/

.DS_Store
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,5 @@ Returns:
- `total_donations_count`
- `total_donors_count`
- `total_recipients_count`

..
107 changes: 70 additions & 37 deletions api/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import base64
import json
import logging
from datetime import datetime
from datetime import datetime, timezone

import requests
from django.conf import settings
Expand Down Expand Up @@ -209,7 +209,7 @@ def post(self, request, list_id: int):
existing_list.cover_image_url = data.get("cover_image_url")
existing_list.admin_only_registrations = data.get("admin_only_registrations", False)
existing_list.default_registration_status = data.get("default_registration_status", "Pending")
existing_list.updated_at = datetime.fromtimestamp(data["updated_at"] / 1000)
existing_list.updated_at = datetime.fromtimestamp(data["updated_at"] / 1000, tz=timezone.utc)
existing_list.save()

# Update admins
Expand All @@ -233,8 +233,8 @@ def post(self, request, list_id: int):
cover_image_url=data.get("cover_image_url"),
admin_only_registrations=data.get("admin_only_registrations", False),
default_registration_status=data.get("default_registration_status", "Pending"),
created_at=datetime.fromtimestamp(data["created_at"] / 1000),
updated_at=datetime.fromtimestamp(data["updated_at"] / 1000),
created_at=datetime.fromtimestamp(data["created_at"] / 1000, tz=timezone.utc),
updated_at=datetime.fromtimestamp(data["updated_at"] / 1000, tz=timezone.utc),
)

# Create owner account
Expand Down Expand Up @@ -303,8 +303,8 @@ def post(self, request, list_id: int):
defaults={
"registered_by_id": reg.get("registered_by", reg["registrant_id"]),
"status": reg.get("status", "Pending"),
"submitted_at": datetime.fromtimestamp(reg["submitted_ms"] / 1000),
"updated_at": datetime.fromtimestamp(reg["updated_ms"] / 1000),
"submitted_at": datetime.fromtimestamp(reg["submitted_ms"] / 1000, tz=timezone.utc),
"updated_at": datetime.fromtimestamp(reg["updated_ms"] / 1000, tz=timezone.utc),
"admin_notes": reg.get("admin_notes"),
"registrant_notes": reg.get("registrant_notes"),
}
Expand Down Expand Up @@ -372,8 +372,8 @@ def post(self, request, list_id: int, registrant_id: str):
defaults={
"registered_by_id": reg.get("registered_by", reg["registrant_id"]),
"status": reg.get("status", "Pending"),
"submitted_at": datetime.fromtimestamp(reg["submitted_ms"] / 1000),
"updated_at": datetime.fromtimestamp(reg["updated_ms"] / 1000),
"submitted_at": datetime.fromtimestamp(reg["submitted_ms"] / 1000, tz=timezone.utc),
"updated_at": datetime.fromtimestamp(reg["updated_ms"] / 1000, tz=timezone.utc),
"admin_notes": reg.get("admin_notes"),
"registrant_notes": reg.get("registrant_notes"),
}
Expand Down Expand Up @@ -438,10 +438,10 @@ def post(self, request, pot_id: str):
existing_pot.description = config.get("pot_description", "")
existing_pot.max_approved_applicants = config.get("max_projects", 0)
existing_pot.base_currency = config.get("base_currency", "near")
existing_pot.application_start = datetime.fromtimestamp(config["application_start_ms"] / 1000)
existing_pot.application_end = datetime.fromtimestamp(config["application_end_ms"] / 1000)
existing_pot.matching_round_start = datetime.fromtimestamp(config["public_round_start_ms"] / 1000)
existing_pot.matching_round_end = datetime.fromtimestamp(config["public_round_end_ms"] / 1000)
existing_pot.application_start = datetime.fromtimestamp(config["application_start_ms"] / 1000, tz=timezone.utc)
existing_pot.application_end = datetime.fromtimestamp(config["application_end_ms"] / 1000, tz=timezone.utc)
existing_pot.matching_round_start = datetime.fromtimestamp(config["public_round_start_ms"] / 1000, tz=timezone.utc)
existing_pot.matching_round_end = datetime.fromtimestamp(config["public_round_end_ms"] / 1000, tz=timezone.utc)
existing_pot.registry_provider = config.get("registry_provider")
existing_pot.min_matching_pool_donation_amount = config.get("min_matching_pool_donation_amount", "0")
existing_pot.sybil_wrapper_provider = config.get("sybil_wrapper_provider")
Expand All @@ -451,7 +451,7 @@ def post(self, request, pot_id: str):
existing_pot.referral_fee_public_round_basis_points = config["referral_fee_public_round_basis_points"]
existing_pot.chef_fee_basis_points = config["chef_fee_basis_points"]
if config.get("cooldown_end_ms"):
existing_pot.cooldown_end = datetime.fromtimestamp(config["cooldown_end_ms"] / 1000)
existing_pot.cooldown_end = datetime.fromtimestamp(config["cooldown_end_ms"] / 1000, tz=timezone.utc)
existing_pot.all_paid_out = config.get("all_paid_out", False)
existing_pot.protocol_config_provider = config.get("protocol_config_provider")
existing_pot.save()
Expand All @@ -468,29 +468,50 @@ def post(self, request, pot_id: str):
"pot_id": pot_id
})
else:
# Ensure pot factory exists
# Auto-create pot factory if missing
if not PotFactory.objects.filter(account_id=factory_id).exists():
return Response({
"error": f"Pot factory {factory_id} not found in database. Sync the factory first."
}, status=404)
try:
factory_config = fetch_from_rpc("get_config", contract_id=factory_id)
if not factory_config:
return Response({
"error": f"Pot factory {factory_id} not found on chain."
}, status=404)
factory_owner, _ = Account.objects.get_or_create(id=factory_config.get("owner", factory_id))
protocol_fee_recipient, _ = Account.objects.get_or_create(
id=factory_config.get("protocol_fee_recipient_account", factory_config.get("owner", factory_id))
)
PotFactory.objects.create(
account_id=factory_id,
owner=factory_owner,
deployed_at=datetime.now(tz=timezone.utc),
protocol_fee_basis_points=factory_config.get("protocol_fee_basis_points", 0),
protocol_fee_recipient=protocol_fee_recipient,
require_whitelist=factory_config.get("require_whitelist", False),
)
logger.info(f"Auto-created PotFactory {factory_id}")
except Exception as e:
logger.error(f"Failed to auto-create PotFactory {factory_id}: {e}")
return Response({
"error": f"Pot factory {factory_id} not found and auto-creation failed: {e}"
}, status=404)

# Create new pot
pot = Pot.objects.create(
account_id=pot_id,
pot_factory_id=factory_id,
deployer=owner,
deployed_at=datetime.now(),
deployed_at=datetime.now(tz=timezone.utc),
source_metadata=config.get("source_metadata", {}),
owner=owner,
chef=chef,
name=config.get("pot_name", ""),
description=config.get("pot_description", ""),
max_approved_applicants=config.get("max_projects", 0),
base_currency=config.get("base_currency", "near"),
application_start=datetime.fromtimestamp(config["application_start_ms"] / 1000),
application_end=datetime.fromtimestamp(config["application_end_ms"] / 1000),
matching_round_start=datetime.fromtimestamp(config["public_round_start_ms"] / 1000),
matching_round_end=datetime.fromtimestamp(config["public_round_end_ms"] / 1000),
application_start=datetime.fromtimestamp(config["application_start_ms"] / 1000, tz=timezone.utc),
application_end=datetime.fromtimestamp(config["application_end_ms"] / 1000, tz=timezone.utc),
matching_round_start=datetime.fromtimestamp(config["public_round_start_ms"] / 1000, tz=timezone.utc),
matching_round_end=datetime.fromtimestamp(config["public_round_end_ms"] / 1000, tz=timezone.utc),
registry_provider=config.get("registry_provider"),
min_matching_pool_donation_amount=config.get("min_matching_pool_donation_amount", "0"),
sybil_wrapper_provider=config.get("sybil_wrapper_provider"),
Expand Down Expand Up @@ -606,7 +627,8 @@ def post(self, request, pot_id: str):
)

donated_at = datetime.fromtimestamp(
(don.get("donated_at") or don.get("donated_at_ms", 0)) / 1000
(don.get("donated_at") or don.get("donated_at_ms", 0)) / 1000,
tz=timezone.utc,
)

Donation.objects.update_or_create(
Expand Down Expand Up @@ -679,8 +701,8 @@ def post(self, request, pot_id: str):
# Upsert applicant account
applicant, _ = Account.objects.get_or_create(id=app["project_id"])

submitted_at = datetime.fromtimestamp(app["submitted_at"] / 1000)
updated_at = datetime.fromtimestamp(app["updated_at"] / 1000) if app.get("updated_at") else submitted_at
submitted_at = datetime.fromtimestamp(app["submitted_at"] / 1000, tz=timezone.utc)
updated_at = datetime.fromtimestamp(app["updated_at"] / 1000, tz=timezone.utc) if app.get("updated_at") else submitted_at

application, created = PotApplication.objects.update_or_create(
pot=pot,
Expand Down Expand Up @@ -772,7 +794,7 @@ def post(self, request, pot_id: str):

# Also update pot's cooldown_end and all_paid_out from config
if config.get("cooldown_end_ms"):
pot.cooldown_end = datetime.fromtimestamp(config["cooldown_end_ms"] / 1000)
pot.cooldown_end = datetime.fromtimestamp(config["cooldown_end_ms"] / 1000, tz=timezone.utc)
pot.all_paid_out = config.get("all_paid_out", False)
pot.save()

Expand All @@ -784,17 +806,28 @@ def post(self, request, pot_id: str):
# Parse paid_at if present
paid_at = None
if payout.get("paid_at"):
paid_at = datetime.fromtimestamp(payout["paid_at"] / 1000)
paid_at = datetime.fromtimestamp(payout["paid_at"] / 1000, tz=timezone.utc)

PotPayout.objects.update_or_create(
pot=pot,
recipient=recipient,
defaults={
"amount": payout["amount"],
"token": near_token,
"paid_at": paid_at,
}
)
payout_defaults = {
"amount": payout["amount"],
"token": near_token,
"paid_at": paid_at,
}

# Use on_chain_id as lookup if available, otherwise fall back to (pot, recipient)
if payout.get("id") is not None:
payout_defaults["pot"] = pot
payout_defaults["recipient"] = recipient
PotPayout.objects.update_or_create(
on_chain_id=payout["id"],
defaults=payout_defaults,
)
else:
PotPayout.objects.update_or_create(
pot=pot,
recipient=recipient,
defaults=payout_defaults,
)
synced += 1

return Response({
Expand Down Expand Up @@ -862,7 +895,7 @@ def post(self, request, pot_id: str):
for c in all_challenges:
challenger, _ = Account.objects.get_or_create(id=c["challenger_id"])

created_at = datetime.fromtimestamp(c["created_at"] / 1000)
created_at = datetime.fromtimestamp(c["created_at"] / 1000, tz=timezone.utc)

challenge, _ = PotPayoutChallenge.objects.update_or_create(
pot=pot,
Expand Down
Loading
Loading