refactor(dao): wire KoiosDaoReader::list_proposals + use it from vote tool
The first attempt's vote MCP tool inlined a Koios address_info pull helper in tools.rs that needed reqwest + pallas_codec + pallas_primitives as direct deps on aldabra-mcp — which it doesn't have. Compile failed. Cleaner: move the work into the dao crate where those deps already live. - ProposalUtxo gains `lovelace` + `proposal_st_asset_name_hex`. The vote builder needs both to construct the new proposal output. - KoiosDaoReader::list_proposals (was stubbed) now reads cfg.proposal_addr, decodes every UTxO's inline datum to ProposalDatum, and matches the ProposalST asset name against cfg.proposal_st_policy when set, falling back to the first asset on the utxo when not (Sulkta convention is one ProposalST + nothing else). - KoiosAsset.asset_name no longer #[allow(dead_code)] — it's read now. - tools.rs::dao_proposal_vote_unsigned switches to dao_reader.list_proposals + drops the inline pull helper. ~150 LOC simpler.
This commit is contained in:
parent
d9f852d8bd
commit
cc69e0df21
2 changed files with 90 additions and 152 deletions
|
|
@ -44,11 +44,15 @@ pub struct StakeUtxo {
|
|||
pub gov_token_quantity: u64,
|
||||
}
|
||||
|
||||
/// One on-chain proposal at the proposal script address (derived from
|
||||
/// the gov-token policy).
|
||||
/// One on-chain proposal at the proposal script address.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProposalUtxo {
|
||||
pub utxo_ref: String,
|
||||
/// Lovelace at this UTxO. Preserved in vote/cosign/advance outputs.
|
||||
pub lovelace: u64,
|
||||
/// Asset name (hex) of the ProposalST token on this UTxO. Sulkta
|
||||
/// convention is empty bytes; community DAOs may use something else.
|
||||
pub proposal_st_asset_name_hex: String,
|
||||
pub datum: ProposalDatum,
|
||||
}
|
||||
|
||||
|
|
@ -195,18 +199,72 @@ impl DaoReader for KoiosDaoReader {
|
|||
Ok(out)
|
||||
}
|
||||
|
||||
async fn list_proposals(&self, _cfg: &DaoConfig) -> DaoResult<Vec<ProposalUtxo>> {
|
||||
// Proposals live at the proposal script address, which is derived
|
||||
// from the Agora deployment + gov-token-policy parameters. We
|
||||
// don't compute that derivation in Phase 1 (it lands in Phase 4
|
||||
// alongside reference_scripts.rs). For now: return empty + a
|
||||
// tracked-todo string. Real wiring: decode proposal script
|
||||
// hash → bech32 → call address_info → filter to inline-datum
|
||||
// UTxOs → decode ProposalDatum.
|
||||
Err(DaoError::State(
|
||||
"list_proposals pending Phase 4 (proposal script address discovery)"
|
||||
.into(),
|
||||
))
|
||||
async fn list_proposals(&self, cfg: &DaoConfig) -> DaoResult<Vec<ProposalUtxo>> {
|
||||
let proposal_addr = cfg.proposal_addr.as_deref().ok_or_else(|| {
|
||||
DaoError::Config(
|
||||
"DaoConfig.proposal_addr missing — register the DAO with proposal_addr \
|
||||
or run dao_discover_scripts first"
|
||||
.into(),
|
||||
)
|
||||
})?;
|
||||
let infos = self.address_info(proposal_addr).await?;
|
||||
let utxos = infos
|
||||
.into_iter()
|
||||
.next()
|
||||
.map(|i| i.utxo_set)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut out = Vec::new();
|
||||
for u in utxos {
|
||||
// Need an inline datum to be a real proposal UTxO. Skip orphans.
|
||||
let Some(ref d) = u.inline_datum else { continue };
|
||||
let pd = match decode_datum_cbor_hex(&d.bytes) {
|
||||
Ok(pd) => pd,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let datum = match ProposalDatum::from_plutus_data(&pd) {
|
||||
Ok(d) => d,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
// Pick the ProposalST asset name. We don't have the policy id
|
||||
// baked into the trait surface (cfg.proposal_st_policy may or
|
||||
// may not be populated yet), so:
|
||||
// - if cfg.proposal_st_policy IS set, match exactly on it;
|
||||
// - otherwise fall back to "the first asset on the utxo,"
|
||||
// which is right for Sulkta convention (1 ProposalST + 0
|
||||
// other assets) but defends against the case where a
|
||||
// community DAO bundles other tokens in the proposal output.
|
||||
let proposal_st_asset_name_hex = match cfg.proposal_st_policy.as_deref() {
|
||||
Some(target_policy) => u
|
||||
.asset_list
|
||||
.as_ref()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.find_map(|a| {
|
||||
if a.policy_id == target_policy {
|
||||
Some(a.asset_name.clone().unwrap_or_default())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
None => u
|
||||
.asset_list
|
||||
.as_ref()
|
||||
.and_then(|al| al.first())
|
||||
.and_then(|a| a.asset_name.clone())
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
out.push(ProposalUtxo {
|
||||
utxo_ref: format!("{}#{}", u.tx_hash, u.tx_index),
|
||||
lovelace: u.value.parse().unwrap_or(0),
|
||||
proposal_st_asset_name_hex,
|
||||
datum,
|
||||
});
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -235,7 +293,7 @@ struct KoiosUtxo {
|
|||
#[derive(Debug, Deserialize)]
|
||||
struct KoiosAsset {
|
||||
policy_id: String,
|
||||
#[allow(dead_code)]
|
||||
#[serde(default)]
|
||||
asset_name: Option<String>,
|
||||
quantity: String,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue