Skip to content

Duplicate accounts in cw20 initial balances causes unrecoverable inconsistent state #626

@harryscholes

Description

@harryscholes

If initial_balances contains one or more duplicate accounts, these accounts will have the balance of the final balance saved to state, whilst the total_supply will be the sum over all initial balances provided.

pub fn create_accounts(deps: &mut DepsMut, accounts: &[Cw20Coin]) -> StdResult<Uint128> {
let mut total_supply = Uint128::zero();
for row in accounts {
let address = deps.api.addr_validate(&row.address)?;
BALANCES.save(deps.storage, &address, &row.amount)?;
total_supply += row.amount;
}
Ok(total_supply)
}

Example:

#[test]
fn inconsistent_total_supply_with_duplicate_accounts_in_initial_balances() {
    let mut deps = mock_dependencies(&[]);
    let instantiate_msg = InstantiateMsg {
        name: "Cash Token".to_string(),
        symbol: "CASH".to_string(),
        decimals: 9,
        initial_balances: vec![
            Cw20Coin {
                address: String::from("addr0000"),
                amount: Uint128::from(1u128),
            },
            Cw20Coin {
                address: String::from("addr0000"),
                amount: Uint128::from(1u128),
            },
        ],
        mint: None,
        marketing: None,
    };
    let info = mock_info("creator", &[]);
    let env = mock_env();
    instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap();

    let token_info = query_token_info(deps.as_ref()).unwrap();
    assert_eq!(token_info.total_supply, Uint128::new(2));
    assert_eq!(get_balance(deps.as_ref(), "addr0000"), Uint128::new(1));
}

Should we assert that all accounts in initial_balances are unique? Happy to make a PR for this if there is interest.

NB this was found in an audit of Mars protocol in a contract that was forked from the cw-plus cw20-base contract.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions