pub fn provide_liquidity(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    assets: [Asset; 2],
    slippage_tolerance: Option<Decimal>,
) -> Result<Response, ContractError> {
    for asset in assets.iter() {
        asset.assert_sent_native_token_balance(&info)?;
    }

    let pair_info: PairInfo = PAIR_INFO.load(deps.storage)?;
    // we really should do this locally...
    let mut pools: [Asset; 2] =
        pair_info.query_pools(&deps.querier, env.contract.address.clone())?;
    let deposits: [Uint128; 2] = [
        assets
            .iter()
            .find(|a| a.info.equal(&pools[0].info))
            .ok_or_else(|| ContractError::AssetMismatch(pools[0].info.to_string()))?
            .amount,
        assets
            .iter()
            .find(|a| a.info.equal(&pools[1].info))
            .ok_or_else(|| ContractError::AssetMismatch(pools[1].info.to_string()))?
            .amount,
    ];

    let mut res = Response::new()
        .add_attribute("action", "provide_liquidity")
        .add_attribute("assets", format!("{}, {}", assets[0], assets[1]));

    for (i, pool) in pools.iter_mut().enumerate() {
        // If the pool is token contract, then we need to execute TransferFrom msg to receive funds
        if let AssetInfo::Token(contract_addr) = &pool.info {
            res = res.add_message(WasmMsg::Execute {
                contract_addr: contract_addr.to_string(),
                msg: to_binary(&Cw20ExecuteMsg::TransferFrom {
                    owner: info.sender.to_string(),
                    recipient: env.contract.address.to_string(),
                    amount: deposits[i],
                })?,
                funds: vec![],
            });
        } else {
            // If the asset is native token, balance is already increased
            // To calculated properly we should subtract user deposit from the pool
            pool.amount = pool.amount.checked_sub(deposits[i])?;
        }
    }

    // assert slippage tolerance
    assert_slippage_tolerance(&slippage_tolerance, &deposits, &pools)?;

    let total_share = query_supply(&deps.querier, pair_info.liquidity_token.clone())?;
    let share = if total_share == Uint128::zero() {
        // Initial share = collateral amount
        Uint128::new((deposits[0].u128() * deposits[1].u128()).integer_sqrt())
    } else {
        // min(1, 2)
        // 1. sqrt(deposit_0 * exchange_rate_0_to_1 * deposit_0) * (total_share / sqrt(pool_0 * pool_1))
        // == deposit_0 * total_share / pool_0
        // 2. sqrt(deposit_1 * exchange_rate_1_to_0 * deposit_1) * (total_share / sqrt(pool_1 * pool_1))
        // == deposit_1 * total_share / pool_1
        std::cmp::min(
            deposits[0].multiply_ratio(total_share, pools[0].amount),
            deposits[1].multiply_ratio(total_share, pools[1].amount),
        )
    };

    // mint LP token to sender
    let msg = WasmMsg::Execute {
        contract_addr: pair_info.liquidity_token.into(),
        msg: to_binary(&Cw20ExecuteMsg::Mint {
            recipient: info.sender.to_string(),
            amount: share,
        })?,
        funds: vec![],
    };
    let res = res
        .add_attribute("share", share.to_string())
        .add_message(msg);
    Ok(res)
}
/// CONTRACT - should approve contract to use the amount of token
should approve contract to use the amount of token
should approve contract to use the amount of token
pub fn provide_liquidity(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    assets: [Asset; 2],
    slippage_tolerance: Option<Decimal>,
) -> Result<Response, ContractError> {
    for asset in assets.iter() {
        asset.assert_sent_native_token_balance(&info)?;
    }
    let pair_info: PairInfo = PAIR_INFO.load(deps.storage)?;
    // we really should do this locally...
    let mut pools: [Asset; 2] =
        pair_info.query_pools(&deps.querier, env.contract.address.clone())?;
    let deposits: [Uint128; 2] = [
        assets
            .iter()
            .find(|a| a.info.equal(&pools[0].info))
            .ok_or_else(|| ContractError::AssetMismatch(pools[0].info.to_string()))?
            .amount,
        assets
            .iter()
            .find(|a| a.info.equal(&pools[1].info))
            .ok_or_else(|| ContractError::AssetMismatch(pools[1].info.to_string()))?
            .amount,
    ];
    let mut res = Response::new()
        .add_attribute("action", "provide_liquidity")
        .add_attribute("assets", format!("{}, {}", assets[0], assets[1]));
    for (i, pool) in pools.iter_mut().enumerate() {
        // If the pool is token contract, then we need to execute TransferFrom msg to receive funds
        if let AssetInfo::Token(contract_addr) = &pool.info {
            res = res.add_message(WasmMsg::Execute {
                contract_addr: contract_addr.to_string(),
                msg: to_binary(&Cw20ExecuteMsg::TransferFrom {
                    owner: info.sender.to_string(),
                    recipient: env.contract.address.to_string(),
                    amount: deposits[i],
                })?,
                funds: vec![],
            });
        } else {
            // If the asset is native token, balance is already increased
            // To calculated properly we should subtract user deposit from the pool
            pool.amount = pool.amount.checked_sub(deposits[i])?;
        }
    }
    // assert slippage tolerance
    assert_slippage_tolerance(&slippage_tolerance, &deposits, &pools)?;
    let total_share = query_supply(&deps.querier, pair_info.liquidity_token.clone())?;
    let share = if total_share == Uint128::zero() {
        // Initial share = collateral amount
        Uint128::new((deposits[0].u128() * deposits[1].u128()).integer_sqrt())
    } else {
        // min(1, 2)
        // 1. sqrt(deposit_0 * exchange_rate_0_to_1 * deposit_0) * (total_share / sqrt(pool_0 * pool_1))
        // == deposit_0 * total_share / pool_0
        // 2. sqrt(deposit_1 * exchange_rate_1_to_0 * deposit_1) * (total_share / sqrt(pool_1 * pool_1))
        // == deposit_1 * total_share / pool_1
        std::cmp::min(
            deposits[0].multiply_ratio(total_share, pools[0].amount),
            deposits[1].multiply_ratio(total_share, pools[1].amount),
        )
    };
    // mint LP token to sender
    let msg = WasmMsg::Execute {
        contract_addr: pair_info.liquidity_token.into(),
        msg: to_binary(&Cw20ExecuteMsg::Mint {
            recipient: info.sender.to_string(),
            amount: share,
        })?,
        funds: vec![],
    };
    let res = res
        .add_attribute("share", share.to_string())
        .add_message(msg);
    Ok(res)
}
pub fn provide_liquidity ( deps : DepsMut , env : Env , info : MessageInfo , assets : [ Asset ; 2 ] , slippage_tolerance : Option < Decimal > , ) -> Result < Response , ContractError > { for asset in assets . iter ( ) { asset . assert_sent_native_token_balance ( & info ) ? ; } let pair_info : PairInfo = PAIR_INFO . load ( deps . storage ) ? ; // we really should do this locally... let mut pools : [ Asset ; 2 ] = pair_info . query_pools ( & deps . querier , env . contract . address . clone ( ) ) ? ; let deposits : [ Uint128 ; 2 ] = [ assets . iter ( ) . find ( | a | a . info . equal ( & pools [ 0 ] . info ) ) . ok_or_else ( | | ContractError :: AssetMismatch ( pools [ 0 ] . info . to_string ( ) ) ) ? . amount , assets . iter ( ) . find ( | a | a . info . equal ( & pools [ 1 ] . info ) ) . ok_or_else ( | | ContractError :: AssetMismatch ( pools [ 1 ] . info . to_string ( ) ) ) ? . amount , ] ; let mut res = Response :: new ( ) . add_attribute ( " " , " " ) . add_attribute ( " " , format ! ( " " assets [ 0 ] assets [ 1 ] ) ) ; for ( i , pool ) in pools . iter_mut ( ) . enumerate ( ) { // If the pool is token contract, then we need to execute TransferFrom msg to receive funds if let AssetInfo :: Token ( contract_addr ) = & pool . info { res = res . add_message ( WasmMsg :: Execute { contract_addr : contract_addr . to_string ( ) , msg : to_binary ( & Cw20ExecuteMsg :: TransferFrom { owner : info . sender . to_string ( ) , recipient : env . contract . address . to_string ( ) , amount : deposits [ i ] , } ) ? , funds : vec ! [ ] , } ) ; } else { // If the asset is native token, balance is already increased // To calculated properly we should subtract user deposit from the pool pool . amount = pool . amount . checked_sub ( deposits [ i ] ) ? ; } } // assert slippage tolerance assert_slippage_tolerance ( & slippage_tolerance , & deposits , & pools ) ? ; let total_share = query_supply ( & deps . querier , pair_info . liquidity_token . clone ( ) ) ? ; let share = if total_share == Uint128 :: zero ( ) { // Initial share = collateral amount Uint128 :: new ( ( deposits [ 0 ] . u128 ( ) * deposits [ 1 ] . u128 ( ) ) . integer_sqrt ( ) ) } else { // min(1, 2) // 1. sqrt(deposit_0 * exchange_rate_0_to_1 * deposit_0) * (total_share / sqrt(pool_0 * pool_1)) // == deposit_0 * total_share / pool_0 // 2. sqrt(deposit_1 * exchange_rate_1_to_0 * deposit_1) * (total_share / sqrt(pool_1 * pool_1)) // == deposit_1 * total_share / pool_1 std :: cmp :: min ( deposits [ 0 ] . multiply_ratio ( total_share , pools [ 0 ] . amount ) , deposits [ 1 ] . multiply_ratio ( total_share , pools [ 1 ] . amount ) , ) } ; // mint LP token to sender let msg = WasmMsg :: Execute { contract_addr : pair_info . liquidity_token . into ( ) , msg : to_binary ( & Cw20ExecuteMsg :: Mint { recipient : info . sender . to_string ( ) , amount : share , } ) ? , funds : vec ! [ ] , } ; let res = res . add_attribute ( " " , share . to_string ( ) ) . add_message ( msg ) ; Ok ( res ) }
CONTRACT - should approve contract to use the amount of token
CONTRACT - should approve contract to use the amount of token
deps
DepsMut
env
Env
info
MessageInfo
assets
[Asset; 2]
slippage_tolerance
Option<Decimal>
deps
DepsMut
env
Env
info
MessageInfo
assets
[Asset; 2]
slippage_tolerance
Option<Decimal>