Conversation
🔍 Crucible Security ReviewSummaryAdds TF20 - a CW20 wrapper contract for TokenFactory denoms. Provides a standard CW20 interface with token admin functions (mint, burn, force transfer) backed by TokenFactory. Security Assessment
Implementation Quality:
Immunefi Pattern Check
False Report Risk
Code Quality
RecommendationApprove - Well-implemented token wrapper with proper admin controls and validation. |
crucible-burnt
left a comment
There was a problem hiding this comment.
🔍 Crucible Security Review
Summary
CW20-compatible wrapper contract for x/tokenfactory denoms. Provides CW20 standard interface (transfer, allowance, send) over TokenFactory tokens with admin controls for minting, force transfers, and burns.
Security Assessment
- Risk Level: High (handles token operations with admin force capabilities)
Findings:
-
Admin authorization is properly enforced (
src/contract.rs:130-141):assert_admin()correctly checks against stored admin and fails if admin isNone. All admin functions (Mint, ForceTransfer, ForceBurn, ForceSend, UpdateContractAdmin, UpdateTokenFactoryAdmin, ModifyMetadata) callassert_admin(). -
⚠️ send_fromusesinfo.senderinstead ofowneras transfer source (src/contract.rs:397): Insend_from, after deducting allowance fromowner, the_sendcall passesinfo.sender.into_string()as the sender instead ofowner. This means the tokens are transferred FROM the spender, not the owner. This appears to be a bug — should beownerto match CW20 semantics wheresend_fromtransfers tokens from the owner's balance using the spender's allowance. -
_transferand_burnuseMsgForceTransfer/MsgBurnfrom TokenFactory: These are admin-level TF operations. The contract must be the TF denom admin for these to work. This is documented in instantiation comments. -
UpdateContractAdminwith empty string removes admin: Settingnew_adminto empty makes adminNone, permanently disabling admin functions. This is documented behavior but irreversible — consider requiring explicit confirmation or a separateRemoveAdminmessage. -
No
set_contract_versionin migrate: There's no migrate entry point. If contract upgrades are needed, one should be added with proper version tracking. -
Protobuf serialization via
to_json_binaryforAnyMsg.value: TheMsgMint,MsgForceTransfer,MsgBurn, etc. are serialized withto_json_binary. Verify that the chain accepts JSON-encoded protobuf messages inAnyMsg— some chains require binary protobuf encoding. If this hasn't been tested on-chain, this could silently fail. -
No zero-amount check: Transfer, send, burn operations don't check for
amount == 0. While TokenFactory may reject zero amounts, explicit validation provides clearer error messages. -
Allowance deduction ordering is correct:
deduct_allowanceis called before_transfer/_send/_burnin all*_fromfunctions — prevents state manipulation.
Immunefi Pattern Check
- ForceTransfer/ForceBurn are powerful admin operations — admin key compromise would allow arbitrary token theft
- No JWT or signature validation involved
- TokenFactory integration means security depends on proper TF admin setup
False Report Risk
- The
ForceTransferandForceBurnfunctions could attract reports claiming "admin can steal funds" — this is by design for TokenFactory admin functionality. Consider documenting this explicitly. - The
_transferfunction usingMsgForceTransferfor ALL transfers (not just admin-forced ones) might look suspicious but is required because the contract holds TF admin rights and tokens aren't held by the contract.
Code Quality Notes
- Well-structured with clear separation of admin vs user functions
- CW20 allowance integration uses well-tested
cw20-baselibrary - Missing: unit tests, integration tests, event emissions for admin operations
amount.clone()onUint128is unnecessary (it'sCopy) — minor style issue
Status
send_from (item #2) should be investigated — it passes info.sender instead of owner to _send, which would transfer tokens from the wrong address. This is the most critical finding. The rest of the contract follows sound patterns.
No description provided.