def run_trigger(new_logs): """ Look for mints and redeems """ events = [] for ev in get_strategy_events(new_logs): title = '' description = '' if ev.topic_0 == SIG_EVENT_DEFAULT_STRATEGY: title = 'Asset Default Strategy Set ♟️' asset, strat_addr = decode_single('(address,address)', decode_hex(ev.data)) description = ( 'New default strategy for {} has been set to {}').format( SYMBOL_FOR_CONTRACT.get(asset, asset), strat_addr, ) elif ev.topic_0 == SIG_EVENT_STRATEGY_APPROVED: title = 'Strategy Added To Vault 🏦♟️' strat_addr = decode_single('(address)', decode_hex(ev.data)) description = 'New strategy {} has been added to the vault'.format( strat_addr, ) elif ev.topic_0 == SIG_EVENT_STRATEGY_ADDED: title = 'Strategy Added ♘' strat_addr = decode_single('(address)', decode_hex(ev.data)) description = 'https://etherscan.io/address/{}'.format(strat_addr) elif ev.topic_0 == SIG_EVENT_STRATEGY_REMOVED: title = 'Strategy Removed ♞' strat_addr = decode_single('(address)', decode_hex(ev.data)) description = 'https://etherscan.io/address/{}'.format(strat_addr) elif ev.topic_0 == SIG_EVENT_WEIGHTS_UPDATED: title = 'Strategy Weights Updated ⚖️' addresses, weights = decode_single('(address[],uint256[])', decode_hex(ev.data)) for i, address in enumerate(addresses): description += '\n{} {}'.format(address, weights[i]) events.append(event_high(title, description, log_model=ev)) return events
def run_trigger(new_logs): """ Trigger events on Compound Timelock transaction events """ events = [] for ev in get_events(new_logs): summary = "ERROR" action = "ERROR" if ev.topic_0 == SIG_EVENT_QUEUE_TRANSACTION: summary = "Compound Timelock transaction queued ⏲️ 📥" action = "queued" elif ev.topic_0 == SIG_EVENT_CANCEL_TRANSACTION: summary = "Compound Timelock transaction canceled ⏲️ ❌" action = "canceled" elif ev.topic_0 == SIG_EVENT_EXECUTE_TRANSACTION: summary = "Compound Timelock transaction executed ⏲️ 🏃♀️" action = "executed" # They all have the same args so most of thise can be reused # tx_hash = decode_single("(bytes32)", decode_hex(ev.topic_1))[0] target = decode_single("(address)", decode_hex(ev.topic_2))[0] value, signature, data, eta_stamp = decode_single( "(uint256,string,bytes,uint256)", decode_hex(ev.data)) eta = datetime.utcfromtimestamp(eta_stamp) call = decode_call(signature, data) events.append( event_high(summary, "Compound Timelock transaction has been {}\n\n" "**Target**: {}\n" "**ETA**: {} UTC\n" "**Call**: {}".format( action, CONTRACT_ADDR_TO_NAME.get(target, target), eta, call, ), log_model=ev)) return events
def run_trigger(new_logs): """ Compound Timelock changes """ events = [] for ev in get_events(new_logs): if ev.topic_0 == SIG_EVENT_PROPOSAL_CREATED: # ProposalCreated(uint id, address proposer, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, uint startBlock, uint endBlock, string description) ( proposal_id, proposer, targets, values, signatures, calldatas, start_block, end_block, description ) = decode_single( "(uint256,address,address[],uint256[],string[],bytes[],uint256,uint256,string)", decode_hex(ev.data)) details = create_prop_details( proposal_id, description, proposer, targets, signatures, calldatas, start_block, end_block, ) # If the message is too long, truncate description only if len(details) > DISCORD_EMBED_DESCRIPTION_LIMIT: diff = len(details) - DISCORD_EMBED_DESCRIPTION_LIMIT details = create_prop_details( proposal_id, truncate_elipsis(description, max_length=len(description) - diff), proposer, targets, signatures, calldatas, start_block, end_block, ) events.append( event_high( "Compound Governor Proposal Created ({}) 🗳️ 🆕".format( proposal_id), details, log_model=ev)) elif ev.topic_0 == SIG_EVENT_PROPOSAL_CANCELED: proposal_id = decode_single("(uint256)", decode_hex(ev.data))[0] events.append( event_high( "Compound GovernorAlpha proposed cancelled 🗳️ ❌", "Compound GovernorAlpha proposal #{} has been canceled". format(proposal_id), log_model=ev)) elif ev.topic_0 == SIG_EVENT_PROPOSAL_QUEUED: proposal_id, eta_stamp = decode_single("(uint256,uint256)", decode_hex(ev.data)) eta = datetime.utcfromtimestamp(eta_stamp) events.append( event_high( "Compound GovernorAlpha proposed queued 🗳️ 📥", "Compound GovernorAlpha proposal #{} has been queued " "for {} UTC".format( proposal_id, eta, ), log_model=ev)) elif ev.topic_0 == SIG_EVENT_PROPOSAL_EXECUTED: proposal_id = decode_single("(uint256)", decode_hex(ev.data))[0] events.append( event_high( "Compound GovernorAlpha proposed executed 🗳️ ⚙️", "Compound GovernorAlpha proposal #{} has been executed". format(proposal_id, ), log_model=ev)) # This is a ton of noise that's probably irrelevant to us. Will leave # it here in case we change our minds. # # elif ev.topic_0 == SIG_EVENT_VOTE_CAST: # # VoteCast(address voter, uint proposalId, bool support, uint votes) # ( # voter, # proposal_id, # support, # votes # ) = decode_single( # "(address,uint256,bool,uint256)", # decode_hex(ev.data) # ) # events.append(event_low( # "Compound GovernorAlpha vote 🗳️", # "{} has voted {} of proposal #{}".format( # voter, # "in support ✔️" if support else "in opposition ❌", # proposal_id, # ) # )) return events
def run_trigger(new_logs): """ Template trigger """ events = [] for ev in get_events(new_logs): if ev.topic_0 == SIG_EVENT_START_VOTE: # StartVote( # uint256 indexed voteId, # address indexed creator, # string metadata, # uint256 minBalance, # uint256 minTime, # uint256 totalSupply, # uint256 creatorVotingPower # ) vote_id = decode_single('(uint256)', decode_hex(ev.topic_1))[0] creator = decode_single('(address)', decode_hex(ev.topic_2))[0] ( metadata_hash, min_balance, min_time, total_supply, creator_voting_power, ) = decode_single("(string,uint256,uint256,uint256,uint256)", decode_hex(ev.data)) metadata = fetch_ipfs_json( strip_terrible_ipfs_prefix(metadata_hash)) """ 51% Voting contract is for contract deployments and 60% Voting contract is for parameter changes """ vote_url = 'https://dao.curve.fi/vote/{}/{}'.format( 'ownership' if ev.address == CURVE_ARAGON_51 else 'parameter', vote_id, ) details = ("**Creator**: {} \n" "**Creator Voting Power**: {} veCRV\n" "**Minimum vote balance**: {} veCRV\n" "**Current total supply**: {} veCRV\n" "**Minimum time**: {}\n" "**Metadata**: {}\n\n" "{}").format( creator, format_token_human('veCRV', creator_voting_power), format_token_human('veCRV', min_balance), format_token_human('veCRV', total_supply), format_timedelta(timedelta(seconds=min_time)), metadata.get('text', 'NO METADATA TEXT FOUND.'), vote_url, ) events.append( event_high("{} - Vote Created ({}) 🗳️ 🆕".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address), vote_id, ), details, log_model=ev)) elif ev.topic_0 == SIG_EVENT_EXECUTE_VOTE: # ExecuteVote(uint256 indexed voteId) vote_id = decode_single('(uint256)', decode_hex(ev.topic_1))[0] events.append( event_high( "{} - Vote Executed ({}) 🗳️ ⚙️".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address), vote_id, ), "Curve Aragon DAO vote #{} on the {} voting app has been " "executed".format( vote_id, CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address), ), log_model=ev)) elif ev.topic_0 == SIG_EVENT_SCRIPT_RESULT: # ScriptResult( # address indexed executor, # bytes script, # bytes input, # bytes returnData # ) executor = decode_single('(address)', decode_hex(ev.topic_1))[0] # script, input_data, return_data = decode_single( # "(bytes,bytes,bytes)", # decode_hex(ev.data), # ) """ TODO: Decode this further? Right now I don't think it's worth the effort, though we're putting a bit of trust into the prop that it's nothing nefarious. Might be worth coming back to this. Only problem is that it appears to be EVM-level instructions... Ref: https://hack.aragon.org/docs/evmscript_EVMScriptRunner Ref: https://github.com/aragon/aragonOS/blob/f3ae59b00f73984e562df00129c925339cd069ff/contracts/evmscript/EVMScriptRunner.sol#L34-L100 """ # print('script', script) # print('input_data:', input_data) # print('return_data:', return_data) events.append( event_normal("{} - Execution Result 🗳️ 🪣".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address)), "Executed by: {}".format(executor), log_model=ev)) return events
def run_trigger(new_logs): """ Template trigger """ events = [] for ev in get_events(new_logs): if ev.topic_0 == SIG_EVENT_CHANGE_SUPPORT_REQUIRED: # ChangeSupportRequired(uint64 supportRequiredPct) support_required = decode_single('(uint64)', decode_hex(ev.data))[0] events.append( event_high( "{} - Support Required Changed 🎚️".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address)), "{}% support is now required for a vote pass. \n\n" "NOTE: This is unexpected due to two contracts for different " "voting levels.".format(Decimal(support_required) / E_18), log_model=ev)) elif ev.topic_0 == SIG_EVENT_CHANGE_MIN_QUORUM: # ChangeMinQuorum(uint64 minAcceptQuorumPct) min_quorum = decode_single('(uint64)', decode_hex(ev.data))[0] events.append( event_normal( "{} - Support Minimum Quorum 🎚️".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address)), "{}% quorum (yeas out of total supply) is now required for a vote." .format(Decimal(min_quorum) / E_18), log_model=ev)) elif ev.topic_0 == SIG_EVENT_MIN_BALANCE_SET: # MinimumBalanceSet(uint256 minBalance) min_balance = decode_single('(uint256)', decode_hex(ev.data))[0] events.append( event_normal( "{} - Minimum Balance 🎚️".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address)), "Minimum balance of {} is now required to create a governance " "vote.".format(format_token_human('veCRV', min_balance)), log_model=ev)) elif ev.topic_0 == SIG_EVENT_MIN_TIME_SET: # MinimumTimeSet(uint256 minTime) min_time = decode_single('(uint256)', decode_hex(ev.data))[0] events.append( event_normal( "{} - Minimum Time 🕓".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address)), "Governance vote creation rate limit has been changed to " "{}.".format(format_timedelta( timedelta(seconds=min_time))), log_model=ev)) elif ev.topic_0 == SIG_EVENT_SET_APP: # SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app) namespace = decode_single('(bytes32)', decode_hex(ev.topic_1))[0] app_id = decode_single('(bytes32)', decode_hex(ev.topic_1))[0] app_address = decode_single('(address)', decode_hex(ev.data))[0] events.append( event_high( "{} - New App Set 📛".format( CONTRACT_ADDR_TO_NAME.get(ev.address, ev.address)), "A new Aragon app has been set for the Curve Voting Fork. " "This is expected to only happen on app creation.\n\n" "Namespace: {}\n" "App ID: {}\n" "App Address: {}\n".format( namespace, app_id, app_address, ), log_model=ev)) return events
def run_trigger(new_logs): """ Compound Timelock changes """ events = [] for ev in get_events(new_logs): if ev.topic_0 == SIG_EVENT_AAVE_PROPOSAL_CREATED: """ event ProposalCreated( uint256 indexed proposalId, bytes32 indexed ipfsHash, bytes32 indexed proposalType, uint256 propositionPowerOfCreator, uint256 threshold, uint256 maxMovesToVotingAllowed, uint256 votingBlocksDuration, uint256 validatingBlocksDuration, address proposalExecutor ) """ proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] ipfs_hash = decode_single("(bytes32)", decode_hex(ev.topic_2))[0] # proposal_type = decode_single( # "(bytes32)", # decode_hex(ev.topic_3) # )[0] ( proposition_power_of_creator, threshold, max_moves_to_voting_allowed, voting_blocks_duration, validating_blocks_duration, proposal_executor, ) = decode_single( "(uint256,uint256,uint256,uint256,uint256,address)", decode_hex(ev.data)) b58_ipfs_data = decode_ipfs_hash(encode_hex(ipfs_hash)) ipfs_data = fetch_ipfs_json(b58_ipfs_data) prop_headers = parse_prop_headers(ipfs_data) aip = prop_headers.get('aip') if aip: aip_link = 'https://aave.github.io/aip/AIP-{}'.format(aip) else: aip_link = '[UNKNOWN AIP]' events.append( event_high( "Aave (v1) Governance Proposal Created (ID: {}) 🗳️ 🆕". format(proposal_id), "A new proposal (ID: {}) has been submitted for Aave" "\n\n" "**Title**: {}\n" "**Description**: {}\n\n" "**Threshold**: {} AAVE\n" "**Voting Duration** {} blocks (approx {} days)\n" "**Validating Duration** {} blocks (approx {} days)\n" "**Executor**: {}\n" "**IPFS Hash**: {}\n" "{}".format( proposal_id, ipfs_data.get('title'), ipfs_data.get('shortDescription'), format_token_human('AAVE', Decimal(threshold)), voting_blocks_duration, round( Decimal(voting_blocks_duration) / BLOCKS_PER_DAY, 2), validating_blocks_duration, round( Decimal(validating_blocks_duration) / BLOCKS_PER_DAY, 2), proposal_executor, decode_ipfs_hash(encode_hex(ipfs_hash)), aip_link, ), log_model=ev)) elif ev.topic_0 == SIG_EVENT_STATUS_CHANGE_TO_VALIDATING: # StatusChangeToValidating(uint256 indexed proposalId) proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] events.append( event_high( "Aave proposal moved to validating 🗳️ 🔍", "Aave proposal #{} is now in validating stage awaiting " "challenges".format(proposal_id), log_model=ev)) elif ev.topic_0 == SIG_EVENT_STATUS_CHANGE_TO_VOTING: """ StatusChangeToVoting( uint256 indexed proposalId, uint256 movesToVoting ) """ proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] events.append( event_high("Aave proposal moved to voting 🗳️ 📥", "Aave proposal #{} is now in voting stage".format( proposal_id), log_model=ev)) elif ev.topic_0 == SIG_EVENT_STATUS_CHANGE_TO_EXECUTED: """ StatusChangeToExecuted(uint256 indexed proposalId) """ proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] events.append( event_normal("Aave proposal has been resolved 🗳️ ⚙️", "Aave proposal #{} has now been resolved".format( proposal_id), log_model=ev)) elif ev.topic_0 == SIG_EVENT_WINS_YES: """ YesWins( uint256 indexed proposalId, uint256 abstainVotingPower, uint256 yesVotingPower, uint256 noVotingPower ) """ proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] events.append( event_high( "Aave proposal has been passed 🗳️ ✅", "Aave proposal #{} has been passed".format(proposal_id), log_model=ev)) elif ev.topic_0 == SIG_EVENT_WINS_NO: """ NoWins( uint256 indexed proposalId, uint256 abstainVotingPower, uint256 yesVotingPower, uint256 noVotingPower ) """ proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] events.append( event_high( "Aave proposal has failed 🗳️ ❎", "Aave proposal #{} has been rejected".format(proposal_id), log_model=ev)) elif ev.topic_0 == SIG_EVENT_WINS_ABSTAIN: """ AbstainWins( uint256 indexed proposalId, uint256 abstainVotingPower, uint256 yesVotingPower, uint256 noVotingPower ) """ proposal_id = decode_single("(uint256)", decode_hex(ev.topic_1))[0] events.append( event_high( "Aave proposal has failed by abstention 🗳️ 〰️", "Aave proposal #{} has been rejected by abstention".format( proposal_id), log_model=ev)) return events