It’s time to dive deep into writing our smart contracts for the [carbon] swap, it’s pretty straightforward in what I’m trying to do, but I’ve been facing a couple of bugs in integrating with Balancer which is blocking any progress I’m having. But before we go into that, let’s explore a bit more into what exactly I’m trying to build here.

T[C]S is a ReFi-based project that helps you save the planet. It introduces an AMM that owns its liquidity, by bonding LPs with a reserve currency $TCT (The Carbon Tether). $TCT would work as a bonded reserve currency that is backed by the AMM pool of carbon assets. Hence potentially acting as the go-to carbon asset which encompasses value from all of the major on-chain Carbon Bridging protocols like Toucan Protocol, and Moss Earth.
Liquidity providers deposit their liquidity to mint fresh TCT backed 1:1 to the number of metric tonnes of CO2 the Liquidity represents. This is done to reduce the fragmentation of carbon on-chain and to bring a unified price of carbon on-chain.
In the above image, you may notice that we have the carbon-asset tokens like BCT, NCT, MCO2, in a Composable Stable Pool, this is because we assume their price are relatively correlated as they all represent carbon, and we compose them with weighted pools of USDC, and TCT itself for a more efficient AMM experience.
I might explore the use of a pool like bb-a-USD rather than simply USDC, as it allows to efficiently interact with Linear Pools of USDC, USDT, and DAI. Hence, showcasing the powerful composability of Balancer.

The above image depicts how I’m planning to architect the smart contracts to interact with Balancer. The T[C]S factory gets the user deposits and join the Balancer Pools as the owner itself and receiver the BPT. Upon receiving this the T[C]S Factory mints TCT for the LP. A similar process would occur upon exiting the pools. The TCT is burnt, and underlying token is released.
A trader on the other hand would ideally use the frontend to interact with the Balancer VAULT directly without any middleware contract.
Now that we have an idea on what we want, it’s time to build it out. I started writing my contract to join the Balancer pool, while trying to implement the feature I had talked about above (owning liquidity and minting TCT), but I came across a few issues when interfacing with the Balancer Vault, which is still unresolved as I type.
So I initially coded my function to join a Balancer Pool to be done with the user funds going directly to the Vault and the receiver of the BPT to be my contract, but this resulted in me receiving a BAL#401-SENDER_NOT_ALLOWED error . This took me a few days to figure out but, the way Balancer is set up, a contract needs to be approved by the Balancer DAO to act as a Relayer for a user and must be assigned that role, to be able to do this. This was a hassle, and I needed a better way to achieve what I wanted to do.
So now my alternative approach is to IERC20.transferFrom() the tokens to be deposited to my contract first, which makes the contract own the tokens and then subsequently join the pool with joinPool(), by doing this there is no need for a relayer because the owner itself is handling the tokens.
But again, now I have come across a different error which was BAL#103-INPUT_LENGTH_MISMATCH. This meant somewhere in my input for the JoinPoolRequest, I am making some mistake, but upon further investigation I couldn’t pinpoint the exact issue. The struct for the request is as follows:
joinPool(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest request
)
struct JoinPoolRequest {
address[] assets,
uint256[] maxAmountsIn,
bytes userData,
bool fromInternalBalance
}
The reply I got from Discord might’ve helped to get rid of this error, but again resulted in another one, which I was not able to decipher BAL#001-SUB_OVERFLOW.

I’m still stuck at this point, and with the Fellowship ending next week, I’m not sure how much I’ll be able to complete if this core function is not working as intended.
Meanwhile, I’ll start working on the frontend of the project, while also simultaneously trying to solve this bug.
Catch you next week!

