Skip to content

Instantly share code, notes, and snippets.

@richardliang
Last active January 23, 2022 08:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardliang/f7b136c2e3f70f5310bbef102446707d to your computer and use it in GitHub Desktop.
Save richardliang/f7b136c2e3f70f5310bbef102446707d to your computer and use it in GitHub Desktop.
const { DefenderRelaySigner, DefenderRelayProvider } = require('defender-relay-client/lib/ethers');
const { Relayer } = require('defender-relay-client');
const { ethers } = require("ethers");
const abi = [{"inputs":[{"internalType":"contract IBaseManager","name":"_manager","type":"address"},{"components":[{"internalType":"contract ISetToken","name":"setToken","type":"address"},{"internalType":"contract IPerpV2LeverageModule","name":"perpV2LeverageModule","type":"address"},{"internalType":"contract IAccountBalance","name":"perpV2AccountBalance","type":"address"},{"internalType":"contract IChainlinkAggregatorV3","name":"basePriceOracle","type":"address"},{"internalType":"contract IChainlinkAggregatorV3","name":"quotePriceOracle","type":"address"},{"internalType":"address","name":"virtualBaseAddress","type":"address"},{"internalType":"address","name":"virtualQuoteAddress","type":"address"}],"internalType":"struct PerpV2LeverageStrategyExtension.ContractSettings","name":"_strategy","type":"tuple"},{"components":[{"internalType":"int256","name":"targetLeverageRatio","type":"int256"},{"internalType":"int256","name":"minLeverageRatio","type":"int256"},{"internalType":"int256","name":"maxLeverageRatio","type":"int256"},{"internalType":"uint256","name":"recenteringSpeed","type":"uint256"},{"internalType":"uint256","name":"rebalanceInterval","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.MethodologySettings","name":"_methodology","type":"tuple"},{"components":[{"internalType":"uint256","name":"slippageTolerance","type":"uint256"},{"internalType":"uint256","name":"twapCooldownPeriod","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.ExecutionSettings","name":"_execution","type":"tuple"},{"components":[{"internalType":"uint256","name":"etherReward","type":"uint256"},{"internalType":"int256","name":"incentivizedLeverageRatio","type":"int256"},{"internalType":"uint256","name":"incentivizedSlippageTolerance","type":"uint256"},{"internalType":"uint256","name":"incentivizedTwapCooldownPeriod","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.IncentiveSettings","name":"_incentive","type":"tuple"},{"components":[{"internalType":"uint256","name":"twapMaxTradeSize","type":"uint256"},{"internalType":"uint256","name":"incentivizedTwapMaxTradeSize","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.ExchangeSettings","name":"_exchange","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"_status","type":"bool"}],"name":"AnyoneCallableUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_caller","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"CallerStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"_currentLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_newLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_chunkRebalanceNotional","type":"int256"},{"indexed":false,"internalType":"int256","name":"_totalRebalanceNotional","type":"int256"}],"name":"Disengaged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"_currentLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_newLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_chunkRebalanceNotional","type":"int256"},{"indexed":false,"internalType":"int256","name":"_totalRebalanceNotional","type":"int256"}],"name":"Engaged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_twapMaxTradeSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_incentivizedTwapMaxTradeSize","type":"uint256"}],"name":"ExchangeSettingsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_twapCooldownPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_slippageTolerance","type":"uint256"}],"name":"ExecutionSettingsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_etherReward","type":"uint256"},{"indexed":false,"internalType":"int256","name":"_incentivizedLeverageRatio","type":"int256"},{"indexed":false,"internalType":"uint256","name":"_incentivizedSlippageTolerance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_incentivizedTwapCooldownPeriod","type":"uint256"}],"name":"IncentiveSettingsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"_targetLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_minLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_maxLeverageRatio","type":"int256"},{"indexed":false,"internalType":"uint256","name":"_recenteringSpeed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_rebalanceInterval","type":"uint256"}],"name":"MethodologySettingsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"_currentLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_newLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_chunkRebalanceNotional","type":"int256"},{"indexed":false,"internalType":"int256","name":"_totalRebalanceNotional","type":"int256"}],"name":"RebalanceIterated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"_currentLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_newLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_chunkRebalanceNotional","type":"int256"},{"indexed":false,"internalType":"int256","name":"_totalRebalanceNotional","type":"int256"}],"name":"Rebalanced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"_currentLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_newLeverageRatio","type":"int256"},{"indexed":false,"internalType":"int256","name":"_rebalanceNotional","type":"int256"},{"indexed":false,"internalType":"uint256","name":"_etherIncentive","type":"uint256"}],"name":"RipcordCalled","type":"event"},{"inputs":[],"name":"anyoneCallable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"callAllowList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralUnits","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disengage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"engage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getChunkRebalanceNotional","outputs":[{"internalType":"int256","name":"size","type":"int256"},{"internalType":"address","name":"sellAsset","type":"address"},{"internalType":"address","name":"buyAsset","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEtherIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentLeverageRatio","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExchangeSettings","outputs":[{"components":[{"internalType":"uint256","name":"twapMaxTradeSize","type":"uint256"},{"internalType":"uint256","name":"incentivizedTwapMaxTradeSize","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.ExchangeSettings","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExecution","outputs":[{"components":[{"internalType":"uint256","name":"slippageTolerance","type":"uint256"},{"internalType":"uint256","name":"twapCooldownPeriod","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.ExecutionSettings","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIncentive","outputs":[{"components":[{"internalType":"uint256","name":"etherReward","type":"uint256"},{"internalType":"int256","name":"incentivizedLeverageRatio","type":"int256"},{"internalType":"uint256","name":"incentivizedSlippageTolerance","type":"uint256"},{"internalType":"uint256","name":"incentivizedTwapCooldownPeriod","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.IncentiveSettings","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMethodology","outputs":[{"components":[{"internalType":"int256","name":"targetLeverageRatio","type":"int256"},{"internalType":"int256","name":"minLeverageRatio","type":"int256"},{"internalType":"int256","name":"maxLeverageRatio","type":"int256"},{"internalType":"uint256","name":"recenteringSpeed","type":"uint256"},{"internalType":"uint256","name":"rebalanceInterval","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.MethodologySettings","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategy","outputs":[{"components":[{"internalType":"contract ISetToken","name":"setToken","type":"address"},{"internalType":"contract IPerpV2LeverageModule","name":"perpV2LeverageModule","type":"address"},{"internalType":"contract IAccountBalance","name":"perpV2AccountBalance","type":"address"},{"internalType":"contract IChainlinkAggregatorV3","name":"basePriceOracle","type":"address"},{"internalType":"contract IChainlinkAggregatorV3","name":"quotePriceOracle","type":"address"},{"internalType":"address","name":"virtualBaseAddress","type":"address"},{"internalType":"address","name":"virtualQuoteAddress","type":"address"}],"internalType":"struct PerpV2LeverageStrategyExtension.ContractSettings","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"iterateRebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastTradeTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract IBaseManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ripcord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"twapMaxTradeSize","type":"uint256"},{"internalType":"uint256","name":"incentivizedTwapMaxTradeSize","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.ExchangeSettings","name":"_newExchangeSettings","type":"tuple"}],"name":"setExchangeSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"slippageTolerance","type":"uint256"},{"internalType":"uint256","name":"twapCooldownPeriod","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.ExecutionSettings","name":"_newExecutionSettings","type":"tuple"}],"name":"setExecutionSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"etherReward","type":"uint256"},{"internalType":"int256","name":"incentivizedLeverageRatio","type":"int256"},{"internalType":"uint256","name":"incentivizedSlippageTolerance","type":"uint256"},{"internalType":"uint256","name":"incentivizedTwapCooldownPeriod","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.IncentiveSettings","name":"_newIncentiveSettings","type":"tuple"}],"name":"setIncentiveSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"targetLeverageRatio","type":"int256"},{"internalType":"int256","name":"minLeverageRatio","type":"int256"},{"internalType":"int256","name":"maxLeverageRatio","type":"int256"},{"internalType":"uint256","name":"recenteringSpeed","type":"uint256"},{"internalType":"uint256","name":"rebalanceInterval","type":"uint256"}],"internalType":"struct PerpV2LeverageStrategyExtension.MethodologySettings","name":"_newMethodologySettings","type":"tuple"}],"name":"setMethodologySettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shouldRebalance","outputs":[{"internalType":"enum PerpV2LeverageStrategyExtension.ShouldRebalance","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"_customMinLeverageRatio","type":"int256"},{"internalType":"int256","name":"_customMaxLeverageRatio","type":"int256"}],"name":"shouldRebalanceWithBounds","outputs":[{"internalType":"enum PerpV2LeverageStrategyExtension.ShouldRebalance","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"twapLeverageRatio","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateAnyoneCallable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_callers","type":"address[]"},{"internalType":"bool[]","name":"_statuses","type":"bool[]"}],"name":"updateCallerStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralUnits","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawEtherBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
const strategyExtensionAddress = "0xPERP_STRATEGY_ADDRESS";
exports.handler = async function(credentials) {
const relayer = new Relayer(credentials);
const pendingTransactions = await relayer.list({
since: new Date(Date.now() - 60 * 60 * 24),
status: 'pending',
limit: 5,
});
// If tx is pending do not resend. Defender will auto bump the pending txs price until it is included.
if (pendingTransactions.length > 0) {
return -1;
}
const provider = new DefenderRelayProvider(credentials);
const signer = new DefenderRelaySigner(credentials, provider, { speed: 'fast' });
return rebalance(signer, strategyExtensionAddress);
}
const rebalance = async (signer, strategyExtensionAddress) => {
const strategyExtension = new ethers.Contract(strategyExtensionAddress, abi, signer);
const [exchangeNames, rebalEnums] = await strategyExtension.shouldRebalanceWithBounds(
ethers.utils.parseEther("1.7"),
ethers.utils.parseEther("2.3")
);
if (shouldRebalance === 1) {
const tx = await strategyExtension.rebalance({ gasLimit: 1000000});
return tx;
} else if (shouldRebalance === 2) {
const tx = await strategyExtension.iterateRebalance({ gasLimit: 1000000});
return tx;
} else if (shouldRebalance === 3) {
const tx = await strategyExtension.ripcord({ gasLimit: 1000000});
return tx;
}
return shouldRebalance;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment