DSProxy Actions

ETH proxy actions contract address 0x6f0B967a8200c764d09A781397A28f0A0Ec259c0

Polygon proxy actions contract address 0x5FbDB2315678afecb367f032d93F642f64180aa3

In order to atomically perform transactions that involve both issuance and the AMM, a number of proxy actions have been constructed, covering in particular collateral-derivative swaps and adding/removing AMM liquidity.

Issuance and AMM

/// @title CompliFi direct and composite AMM and issuance methods
contract ProxyActions {
/// @notice Mint derivatives by depositing collateral to vault
function mint(
address _vault,
uint256 _collateralAmount
) external {...}
/// @notice Redeem a symmetric portfolio of live derivatives for underlying collateral
function refund(
address _vault,
uint256 _tokenAmount
) external {...}
/// @notice Redeem settled derivatives for underlying collateral
function redeem(
address _vault,
uint256 _primaryTokenAmount,
uint256 _complementTokenAmount,
uint256[] memory _underlyingEndRoundHints
) external {...}
/// @notice Withdraw ERC20 token balance
function withdraw(
address _token
) external {...}
/// @notice Withdraw several ERC20 token balances
function withdrawAll(
address[] memory _tokens
) external {...}
/// @notice Add liquidity to AMM pool in identical proportion to pool contents
function joinPool(
address _pool,
uint256 _poolAmountOut,
uint256[2] calldata _maxAmountsIn
) external {...}
/// @notice Swap between derivatives contained in a single AMM pool
function swap(
address _pool,
address _tokenIn,
uint256 _tokenAmountIn,
address _tokenOut,
uint256 _minAmountOut
) external {...}
/// @notice Remove liquidity from AMM pool
function exitPool(
address _pool,
uint256 _poolAmountIn,
uint256[2] calldata _minAmountsOut
) external {...}
/// @notice Swap collateral for a single derivative
function mintAndSwapCollateralToDerivative(
address _pool,
uint256 _collateralAmount,
address _tokenIn, // Unwanted Derivative to be swapped
uint256 _minAmountOut
) external {...}
/// @notice Swap derivative for collateral
function swapDerivativesToCollateral(
address _pool,
address _derivativeIn,
uint256 _derivativeAmount,
uint256 _tokenAmountIn,
address _derivativeOut,
uint256 _derivativeMinAmountOut
) external {...}
// @notice Swap between derivatives in different AMM pools
function tradeBetweenDerivatives(
address _poolFromAddress,
address _derivativeInAddress,
uint256 _derivativeInAmount,
uint256 _derivativeInAmountToSell,
address _derivativeOut,
uint256 _minTokenOutAmountForFirstSwap,
address _poolToAddress,
address _mintedDerivativeToSell,
uint256 _minTokenOutAmountForSecondSwap
) external {...}
/// @notice Use collateral to mint derivatives and add them as liquidity to AMM pool
function mintAndJoinPool(
address _pool,
uint256 _collateralAmount,
address _tokenIn,
uint256 _tokenAmountIn,
address _tokenOut,
uint256 _minAmountOut,
uint256 _minPoolAmountOut
) external {...}
/// @notice Remove settled derivatives from AMM pool redeem for collateral
/// @dev User provides amount of LP tokens (method applies only when state = Settled)
function removeLiquidityOnSettledState(
address _pool,
uint256 _poolAmountIn,
uint256[2] calldata _minAmountsOut,
uint256[] memory _underlyingEndRoundHints
) external {...}
/// @notice Remove live derivatives from pool and redeem symmetric portion for collateral
/// @dev User provides amount of LP tokens (method applies only when state = Live)
function removeLiquidityOnLiveOrMintingState(
address _pool,
uint256 _poolAmountIn,
address _tokenIn,
uint256 _tokenAmountIn,
uint256 _minAmountOut,
uint256[2] calldata _minAmountsOut
) external {...}
/// @notice Withdraw derivative balances from proxy contract to user's account
function extractChange(address _pool) external {...}
}

Liquidity Mining

/// @title CompliFi liquidity mining methods
contract ProxyActionsLiquidityMining {
/// @notice Deposit tokens to a farm
function deposit(
address _liquidityMining,
address _token,
uint256 _tokenAmount
) external {...}
/// @notice Withdraw deposited tokens
function withdraw(
address _liquidityMining,
address _token,
uint256 _tokenAmount
) external {...}
/// @notice Claim unlocked rewards
function claim(
address _liquidityMining
) external {...}
}

Liquidity Mining Methods - Example

Get user's DSProxy and create a contract:

const PROXY_REGISTRY_ADDR = "0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4"; // Maker DsProxy registry
const PROXY_REGISTRY_ABI = [...]; // DsProxy basic ABI
const PROXY_REGISTRY_CONTRACT = new ethers.Contract(PROXY_REGISTRY_ADDR, PROXY_REGISTRY_ABI);
const signer = ethers.getDefaultProvider().getSigner();
const userProxyAddress = await PROXY_REGISTRY_CONTRACT.proxies(userAddress);
const PROXY_ABI = [{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"},{"name":"_data","type":"bytes"}],"name":"execute","outputs":[{"name":"response","type":"bytes32"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes"},{"name":"_data","type":"bytes"}],"name":"execute","outputs":[{"name":"target","type":"address"},{"name":"response","type":"bytes32"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"cache","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_cacheAddr","type":"address"}],"name":"setCache","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_cacheAddr","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"}];
const proxyContract = new ethers.Contract(userProxyAddress, PROXY_ABI, signer);

Initialize related actions contract (liquidity mining actions as an example):

const PROXY_ACTIONS_ABI = [{"inputs":[{"internalType":"address","name":"_liquidityMining","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidityMining","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidityMining","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}];
async function executeProxyAction(proxyContract, proxyActionsAddress, functionName, functionParams, gasLimit){
const targetContract = new ethers.Contract(proxyActionsAddress, PROXY_ACTIONS_ABI, signer);
const callData = targetContract.interface.encodeFunctionData(functionName, functionParams.map((fp) => fp.value));
try {
const gasEstimation = (await proxyContract.estimateGas['execute(address,bytes)'](proxyActionsAddress, callData)) * 1;
if (gasEstimation) {
gasLimit = Math.max(gasLimit || 0, gasEstimation);
}
console.log('Gas estimate: %s', gasEstimation);
} catch (error) {
console.log(error);
}
console.log('Gas limit: %s', gasLimit);
proxyContract['execute(address,bytes)'](proxyActionsAddress, callData, {
gasLimit: gasLimit || undefined,
})
.then(function(t) {
return ethers.getDefaultProvider().waitForTransaction(t.hash)
})
.catch(x => {
console.log(x);
_print('Something went wrong.')
});
}
function truncN(value, n) {
return Math.trunc(value * Math.pow(10, n)) / Math.pow(10, n);
}
function trunc6(value) {
return truncN(value, 6);
}

Executing CompliFi liquidity mining methods:

async function deposit(proxyContract, proxyActionsAddress, miningAddress, tokenAddress, tokenAmount) {
const functionName = 'deposit';
const functionParams = [
{
name: 'liquidityMiningAddress',
type: 'address',
value: miningAddress,
},
{
name: 'tokenAddress',
type: 'address',
value: tokenAddress,
},
{
name: 'tokenAmount',
type: 'uint256',
value: tokenAmount.toString(),
},
];
return executeProxyAction(
proxyContract,
proxyActionsAddress,
functionName,
functionParams,
250000,
);
}
async function withdraw(proxyContract, proxyActionsAddress, miningAddress, tokenAddress, tokenAmount) {
const functionName = 'withdraw';
const functionParams = [
{
name: 'liquidityMiningAddress',
type: 'address',
value: miningAddress,
},
{
name: 'tokenAddress',
type: 'address',
value: tokenAddress,
},
{
name: 'tokenAmount',
type: 'uint256',
value: tokenAmount.toString(),
},
];
return executeProxyAction(
proxyContract,
proxyActionsAddress,
functionName,
functionParams,
200000,
);
}
async function claim(proxyContract, proxyActionsAddress, miningAddress) {
const functionName = 'claim';
const functionParams = [
{
name: 'liquidityMiningAddress',
type: 'address',
value: miningAddress,
},
];
return executeProxyAction(
proxyContract,
proxyActionsAddress,
functionName,
functionParams,
500000,
);
}