diff --git a/bisenzone-cw-mvp/src/contract.rs b/bisenzone-cw-mvp/src/contract.rs
index f22cc2f..98f718b 100644
--- a/bisenzone-cw-mvp/src/contract.rs
+++ b/bisenzone-cw-mvp/src/contract.rs
@@ -1,7 +1,12 @@
 use cosmwasm_std::{
-    entry_point, to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
+    entry_point, to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response,
+    StdResult, Uint128,
 };
 use cw2::set_contract_version;
+use cw20_base::{
+    contract::{execute_mint, query_balance},
+    state::{MinterData, TokenInfo, TOKEN_INFO},
+};
 
 use crate::error::ContractError;
 use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
@@ -14,7 +19,7 @@ const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
 #[cfg_attr(not(feature = "library"), entry_point)]
 pub fn instantiate(
     deps: DepsMut,
-    _env: Env,
+    env: Env,
     info: MessageInfo,
     _msg: InstantiateMsg,
 ) -> Result<Response, ContractError> {
@@ -24,6 +29,20 @@ pub fn instantiate(
     set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
     STATE.save(deps.storage, &state)?;
 
+    // store token info using cw20-base format
+    let data = TokenInfo {
+        name: "liquidity savings".to_string(),
+        symbol: "!$".to_string(),
+        decimals: 0,
+        total_supply: Uint128::zero(),
+        // set self as minter, so we can properly execute mint and burn
+        mint: Some(MinterData {
+            minter: env.contract.address,
+            cap: None,
+        }),
+    };
+    TOKEN_INFO.save(deps.storage, &data)?;
+
     Ok(Response::new()
         .add_attribute("method", "instantiate")
         .add_attribute("owner", info.sender))
@@ -32,7 +51,7 @@ pub fn instantiate(
 #[cfg_attr(not(feature = "library"), entry_point)]
 pub fn execute(
     deps: DepsMut,
-    _env: Env,
+    env: Env,
     info: MessageInfo,
     msg: ExecuteMsg,
 ) -> Result<Response, ContractError> {
@@ -42,7 +61,9 @@ pub fn execute(
             amount,
             memo,
         } => execute::upload_obligation(deps, info, creditor, amount, memo),
-        ExecuteMsg::ApplyCycle { path, amount } => execute::apply_cycle(deps, path, amount),
+        ExecuteMsg::ApplyCycle { path, amount } => {
+            execute::apply_cycle(deps, env, info, path, amount)
+        }
     }
 }
 
@@ -81,6 +102,8 @@ pub mod execute {
 
     pub fn apply_cycle(
         deps: DepsMut,
+        env: Env,
+        info: MessageInfo,
         path: Vec<String>,
         amount: Uint128,
     ) -> Result<Response, ContractError> {
@@ -98,7 +121,7 @@ pub mod execute {
 
             UTILIZATION.update(
                 deps.storage,
-                (&to, &from),
+                (to, from),
                 |utilization| -> Result<_, ContractError> {
                     let utilization = utilization.unwrap_or_default() - amount;
                     volume_cleared += amount;
@@ -107,6 +130,14 @@ pub mod execute {
                 },
             )?;
         }
+
+        // call into cw20-base to mint the token, call as self as no one else is allowed
+        let sub_info = MessageInfo {
+            sender: env.contract.address.clone(),
+            funds: vec![],
+        };
+        execute_mint(deps, env, sub_info, info.sender.to_string(), volume_cleared)?;
+
         Ok(Response::new()
             .add_attribute("action", "apply_cycle")
             .add_attribute("volume_cleared", format!("{}", volume_cleared)))
@@ -135,6 +166,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
         QueryMsg::GetObligations { creditor } => {
             to_json_binary(&query::get_obligations(deps, creditor)?)
         }
+        QueryMsg::Balance { address } => to_json_binary(&query_balance(deps, address)?),
     }
 }
 
diff --git a/bisenzone-cw-mvp/src/error.rs b/bisenzone-cw-mvp/src/error.rs
index 6989d01..ce3c93c 100644
--- a/bisenzone-cw-mvp/src/error.rs
+++ b/bisenzone-cw-mvp/src/error.rs
@@ -1,4 +1,5 @@
 use cosmwasm_std::StdError;
+use cw20_base::ContractError as Cw20ContractError;
 use thiserror::Error;
 
 #[derive(Error, Debug)]
@@ -14,4 +15,13 @@ pub enum ContractError {
 
     #[error("Amount is greater than utilization")]
     ClearingTooMuch,
+
+    #[error("Cw20 error: {0}")]
+    Cw20(Cw20ContractError),
+}
+
+impl From<Cw20ContractError> for ContractError {
+    fn from(e: Cw20ContractError) -> Self {
+        Self::Cw20(e)
+    }
 }
diff --git a/bisenzone-cw-mvp/src/msg.rs b/bisenzone-cw-mvp/src/msg.rs
index c02a3fa..54c8b47 100644
--- a/bisenzone-cw-mvp/src/msg.rs
+++ b/bisenzone-cw-mvp/src/msg.rs
@@ -1,5 +1,7 @@
 use cosmwasm_schema::{cw_serde, QueryResponses};
 use cosmwasm_std::Uint128;
+#[allow(unused)]
+use cw20::BalanceResponse;
 
 #[cw_serde]
 pub struct InstantiateMsg;
@@ -23,6 +25,8 @@ pub enum QueryMsg {
     // GetCount returns the current count as a json-encoded number
     #[returns(GetObligationsResponse)]
     GetObligations { creditor: String },
+    #[returns(BalanceResponse)]
+    Balance { address: String },
 }
 
 // We define a custom struct for each query response