Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e6cbb1b
init for rip cars (#476)
metanallok Jul 20, 2026
04ad325
update token logo (#479)
metanallok Jul 25, 2026
c1881a0
Omit repo guard comment when PR comes from fork, always render repo g…
metapileks Aug 5, 2026
6c373b3
Update LOYAL token metadata description and add project links (#482)
cosmicsymmetry Aug 7, 2026
271de9a
immediately mark dao as liquidated on proposal finalization
metapileks Aug 14, 2026
aa4b238
dao resize should include spending limit
metapileks Aug 14, 2026
0382481
force zeroing of spending limit before dao liquidation, if spending l…
metapileks Aug 14, 2026
cfc6196
prevent large spend from launching with stale data
metapileks Aug 15, 2026
01d4e4c
proposal migration should hande draft and live proposals differently
metapileks Aug 15, 2026
66d1ee0
remove LP withdrawal from direct liquidation path - allow liquidation…
metapileks Aug 16, 2026
d084bff
disallow finalization and cancellation of unmigrated proposals
metapileks Aug 16, 2026
2e0006d
prevent pre-migration DAO from running instructions with wrong state
metapileks Aug 16, 2026
ed7331c
minor refactor
metapileks Aug 16, 2026
f5974e1
further spending limit validation
metapileks Aug 16, 2026
695272b
buyback proposal kind - track AMM quote reserves by observation
metapileks Aug 17, 2026
c3d39e7
adjust buyback for jup trigger order
metapileks Aug 17, 2026
eee0ab8
allow spot swap for a liquidated dao
metapileks Aug 17, 2026
a26af32
lock liquidator to metadao multisig vault
metapileks Aug 21, 2026
84036b8
prevent hostile takeover from accepting new team same as old team
metapileks Aug 26, 2026
24d738e
fix(futarchy): forbid team sponsorship of hostile proposals
metapileks Aug 26, 2026
e680091
chore(futarchy): drop unused AlreadyLiquidated error
metapileks Aug 26, 2026
6029616
test(liquidation): dedupe second mint in refund test
metapileks Aug 26, 2026
fcf9612
style(futarchy): cargo fmt
metapileks Aug 27, 2026
8a7b224
fix(futarchy): add liquidation guard to sponsor_proposal
metapileks Aug 28, 2026
f7d5cf3
chore(futarchy): add comment regarding double-liquidation being impos…
metapileks Aug 31, 2026
84eb3be
fix(futarchy): replace is_team_sponsored with sponsored_by for granul…
metapileks Sep 2, 2026
96d5771
fix(futarchy): disable optimistic governance flag on migration
metapileks Sep 2, 2026
a7262e3
feat(futarchy): admin proposal cancellation
metapileks Sep 2, 2026
eb88cd5
chore(futarchy): expose admin approve in SDK, refactor tests
metapileks Sep 2, 2026
e7eded2
move SDK into symlink, drop force from installation path (#488)
metapileks Sep 3, 2026
20443bf
Merge remote-tracking branch 'origin/develop' into pileks/mini-instru…
metapileks Sep 3, 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
50 changes: 32 additions & 18 deletions .github/workflows/repo-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,20 @@ jobs:
node-version: '20.18.0'
cache: 'yarn'

- name: Verify root yarn.lock is up to date
id: yarn_root
continue-on-error: true
run: yarn install --frozen-lockfile --ignore-scripts --non-interactive

# sdk first: the root install links `link:./sdk` and needs sdk/node_modules to exist.
- name: Verify sdk yarn.lock is up to date
id: yarn_sdk
continue-on-error: true
run: |
cd sdk
yarn install --frozen-lockfile --ignore-scripts --non-interactive

- name: Verify root yarn.lock is up to date
id: yarn_root
continue-on-error: true
if: steps.yarn_sdk.outcome == 'success'
run: yarn install --frozen-lockfile --ignore-scripts --non-interactive

- name: Run repository guard checks
id: guard
continue-on-error: true
Expand Down Expand Up @@ -83,24 +85,26 @@ jobs:
echo " - Out of sync with the workspace manifests. Run \`cargo update --workspace\` (or rebuild) and commit the updated \`Cargo.lock\`."
fi

if [ "$YARN_ROOT_OUTCOME" = "success" ]; then
echo "- yarn.lock (root): pass"
else
echo "- yarn.lock (root): fail"
echo " - Root \`yarn.lock\` is out of date. Run \`yarn install\` at the repo root and commit the result."
fi

if [ "$YARN_SDK_OUTCOME" = "success" ]; then
echo "- yarn.lock (sdk): pass"
else
echo "- yarn.lock (sdk): fail"
echo " - \`sdk/yarn.lock\` is out of date. Run \`yarn install\` in \`sdk/\` and commit the result."
echo " - \`yarn install --frozen-lockfile\` failed in \`sdk/\`. Usually \`sdk/yarn.lock\` is out of date: run \`yarn install\` in \`sdk/\` and commit the result. See the step log for the actual error."
fi

if [ "$YARN_ROOT_OUTCOME" = "success" ]; then
echo "- yarn.lock (root): pass"
elif [ "$YARN_ROOT_OUTCOME" = "skipped" ]; then
echo "- yarn.lock (root): skipped (sdk install failed - fix that first)"
else
echo "- yarn.lock (root): fail"
echo " - \`yarn install --frozen-lockfile\` failed at the repo root. Usually the root \`yarn.lock\` is out of date: run \`yarn install\` at the repo root and commit the result. See the step log for the actual error."
fi

if [ "$GUARD_OUTCOME" = "success" ]; then
echo "- Repo guard: pass"
elif [ "$GUARD_OUTCOME" = "skipped" ]; then
echo "- Repo guard: skipped (root yarn install failed - fix that first)"
echo "- Repo guard: skipped (yarn install failed - fix that first)"
else
if [ "$EMERGENCY_BYPASS" = "true" ]; then
echo "- Repo guard: bypassed with \`emergency-override\`"
Expand All @@ -117,21 +121,29 @@ jobs:
fi
} > body.md

# Render the same content on the run's Summary page - visible on
# fork PRs too, where the comment steps below are skipped.
cat body.md >> "$GITHUB_STEP_SUMMARY"

{
echo "body<<EOF"
cat body.md
echo "EOF"
} >> "$GITHUB_OUTPUT"

# Fork PRs get a read-only GITHUB_TOKEN, so the comment steps would 403.
# Skip them there - the "Fail if any check failed" step still gates.
- name: Find existing comment
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
id: find
if: github.event.pull_request.head.repo.full_name == github.repository
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: "<!-- repository-guard -->"

- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
if: github.event.pull_request.head.repo.full_name == github.repository
with:
issue-number: ${{ github.event.pull_request.number }}
comment-id: ${{ steps.find.outputs.comment-id }}
Expand All @@ -153,11 +165,13 @@ jobs:
if [ "$CARGO_OUTCOME" != "success" ]; then
failed+=("Cargo.lock out of sync - run \`cargo update --workspace\` (or rebuild) and commit")
fi
if [ "$YARN_ROOT_OUTCOME" != "success" ]; then
failed+=("root yarn.lock out of date - run \`yarn install\` at repo root and commit")
fi
if [ "$YARN_SDK_OUTCOME" != "success" ]; then
failed+=("sdk yarn.lock out of date - run \`yarn install\` in \`sdk/\` and commit")
failed+=("sdk yarn install failed - usually \`sdk/yarn.lock\` is out of date: run \`yarn install\` in \`sdk/\` and commit")
fi
if [ "$YARN_ROOT_OUTCOME" = "skipped" ]; then
failed+=("root yarn.lock check skipped - fix the sdk install first")
elif [ "$YARN_ROOT_OUTCOME" != "success" ]; then
failed+=("root yarn install failed - usually root \`yarn.lock\` is out of date: run \`yarn install\` at repo root and commit")
fi

# The guard itself (exact-version, age, action-pinning, toolchain
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ External programs required for tests. These are pre-compiled `.so` files in `tes

**"blockstore error"**: `rm -rf .anchor/test-ledger test-ledger`

**Module resolution errors**: `cd sdk && yarn build-local && cd .. && yarn install --force`
**Module resolution errors**: `cd sdk && yarn build-local` (the root `node_modules` entry is a symlink to `sdk/`, so no root reinstall is needed)

**Tests timeout**: Increase `startup_wait` in `Anchor.toml`

Expand Down
32 changes: 8 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,38 +125,23 @@ Reload your shell configuration:
source ~/.zshrc # or source ~/.bash_profile
```

#### 7. Install Dependencies
#### 7. Build Programs and Install Dependencies

Install root project dependencies:
Build all programs, install and build the SDK, install the root dependencies, and lint in one step:

```bash
yarn install
./rebuild.sh
```

Install SDK dependencies and build:
Re-run `./rebuild.sh` after changing program or SDK code so tests run against your latest changes.

```bash
cd sdk
yarn install
yarn build-local
cd ..
```

#### 8. Build Programs

Build all Solana programs:

```bash
anchor build
```

Or build a specific program:
To build a single program on its own:

```bash
anchor build -p programs
anchor build -p futarchy
```

#### 9. Run Tests
#### 8. Run Tests

Run all tests:

Expand Down Expand Up @@ -184,13 +169,12 @@ Then run `anchor test` again.

#### "Cannot find module" errors

If you see module resolution errors, rebuild the SDK:
If you see module resolution errors, rebuild the SDK. The root `node_modules` entry for `@metadaoproject/programs` is a symlink to `sdk/`, so no root reinstall is needed:

```bash
cd sdk
yarn build-local
cd ..
yarn install --force
```

#### Tests timeout or validator doesn't start
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@inquirer/prompts": "7.9.0",
"@ledgerhq/hw-app-solana": "7.10.4",
"@ledgerhq/hw-transport-node-hid": "6.33.4",
"@metadaoproject/programs": "./sdk",
"@metadaoproject/programs": "link:./sdk",
"@metaplex-foundation/mpl-token-metadata": "3.4.0",
"@metaplex-foundation/umi": "0.9.2",
"@metaplex-foundation/umi-bundle-defaults": "0.9.2",
Expand Down
28 changes: 24 additions & 4 deletions programs/futarchy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ pub enum FutarchyError {
SpendingLimitNotDirty,
#[msg("Wrong proposal kind for this instruction")]
InvalidProposalKind,
#[msg("This DAO has already been liquidated")]
AlreadyLiquidated,
#[msg("A spending limit can have at most 10 members")]
TooManySpendingLimitMembers,
#[msg("Invalid liquidator")]
Expand All @@ -118,18 +116,40 @@ pub enum FutarchyError {
EmptyProposalParamsUpdate,
#[msg("Buyback amount exceeds 25% of the treasury")]
BuybackCapExceeded,
#[msg("The total must be an exact multiple of the non-zero per-cycle amount, at least twice over")]
#[msg("Buyback total must be non-zero")]
InvalidBuybackAmount,
#[msg("Cycle frequency must be between 60 seconds and 1 year")]
InvalidBuybackCycleFrequency,
#[msg("Start delay must be at most 30 days")]
InvalidBuybackStartDelay,
#[msg("min_price must be no greater than max_price")]
InvalidBuybackPriceBand,
#[msg("A treasury account is neither a vault-owned quote account nor the treasury's AMM position")]
#[msg(
"A treasury account is neither a vault-owned quote account nor the treasury's AMM position"
)]
InvalidTreasuryAccount,
#[msg("Treasury accounts must be in strictly ascending key order")]
TreasuryAccountsNotSorted,
#[msg("This proposal kind's launch takes no extra accounts")]
UnexpectedLaunchAccounts,
#[msg("Spending limit account is not the canonical spending-limit PDA")]
InvalidSpendingLimitAccount,
#[msg("The DAO's team has changed since this draft was created")]
StaleTeamAddress,
#[msg("Account is not migrated to latest layout")]
AccountNotMigrated,
#[msg("A spending limit's monthly amount must be non-zero")]
InvalidSpendingLimitAmount,
#[msg("A spending limit must have at least one member")]
EmptySpendingLimitMembers,
#[msg("A spending limit's members must be unique")]
DuplicateSpendingLimitMember,
#[msg("A buyback must run at least two cycles")]
InvalidBuybackCycleCount,
#[msg("Invalid team address")]
InvalidTeamAddress,
#[msg("This proposal kind cannot be team-sponsored")]
TeamSponsorshipForbidden,
#[msg("Squads proposal must be in Approved status to be cancelled")]
SquadsProposalNotApproved,
}
11 changes: 0 additions & 11 deletions programs/futarchy/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,14 +262,3 @@ pub struct SyncSpendingLimitEvent {
/// `None` = no limit (removed or never existed).
pub config: Option<InitialSpendingLimit>,
}

#[event]
pub struct ApplyLiquidationEvent {
pub common: CommonFields,
pub dao: Pubkey,
pub proposal: Pubkey,
pub liquidator: Pubkey,
pub base_swept: u64,
pub quote_swept: u64,
pub post_amm_state: FutarchyAmm,
}
4 changes: 4 additions & 0 deletions programs/futarchy/src/instructions/admin_cancel_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ pub struct AdminCancelProposal<'info> {

impl AdminCancelProposal<'_> {
pub fn validate(&self) -> Result<()> {
// Ensure the proposal and DAO are migrated.
Proposal::assert_migrated(&self.proposal.to_account_info())?;
Dao::assert_migrated(&self.dao.to_account_info())?;

// Unblockable proposals are censorship-proof once live: nobody, including
// the council, can cancel them. Reads the create-time snapshot so a
// live proposal keeps the flag it launched with.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub struct AdminEnqueueMultisigProposalApproval<'info> {

impl AdminEnqueueMultisigProposalApproval<'_> {
pub fn validate(&self, _args: &AdminEnqueueMultisigProposalApprovalArgs) -> Result<()> {
// Ensure the DAO is migrated before reading `liquidator`.
Dao::assert_migrated(&self.dao.to_account_info())?;

// On a liquidated DAO the liquidator replaces the admin id as the
// required signer. Enqueueing is the only capability the liquidator
// gains: the approve leg stays permissionless and execution is
Expand Down
Loading
Loading