Skip to content

Instantly share code, notes, and snippets.

@banteg
Created September 29, 2020 12:54
Show Gist options
  • Save banteg/b2a3b78cdd59ea346afc56181e7a07cd to your computer and use it in GitHub Desktop.
Save banteg/b2a3b78cdd59ea346afc56181e7a07cd to your computer and use it in GitHub Desktop.

Issue

yYFI vault's StrategyYFIGovernance was misconfigured for the duration since block 10923319 to block 10954777.

The withdrawal fee parameter was set to 5% instead of intended 0.5% because of a typo. This is a proposal to make the users who withdrew from vault in the mentioned period whole.

Process

First I've gathered all the withdraw(uint256) trace calls to the strategy. There were 23 successful trasnsactions.

select * from `bigquery-public-data.crypto_ethereum.traces`
where date(block_timestamp) >= "2020-09-24"
and to_address = '0x395f93350d5102b6139abfc84a7d6ee70488797c'
and block_number < 10954777 and substr(input, 0, 10) = '0x2e1a7d4d' -- withdraw(uint256)
and status = 1

Then I used that file to calculate the compensation amounts by returning 90% of what went into the TreasuryVault.

import csv
from brownie import chain, Wei
from collections import Counter

def main():
    treasury = '0x93A62dA5a14C80f265DAbC077fCEE437B1a0Efde'
    data = list(csv.DictReader(open('results-20200929-190529.csv')))
    assert len(data) == 23
    total = 0
    comps = Counter()
    for item in data:
        tx = chain.get_transaction(item['transaction_hash'])
        tx.wait(1)
        treasury_event = [x for x in tx.events['Transfer'] if 'dst' in x and x['dst'] == treasury][-1]
        user_event = [x for x in tx.events['Transfer'] if 'dst' in x and x['dst'] == tx.sender][-1]
        comp = int(treasury_event['amt'] * .9)  # refund 4.5%
        comps[user_event['dst']] += comp
        total += comp

    print(f'{Wei(total).to("ether")} yfi to comp to {len(comps)} users')
    with open('yYFI-refund.csv', 'wt') as f:
        csv.writer(f).writerows(comps.most_common())

Result

0x170CCF19d1FE9F1C360A2Ef0e54983F037bB0034,1036554123618423552
0x41339d9825963515E5705Df8d3B0eA98105EBB1C,1012971315975863552
0xC10FA265ce69337EB0eCf7B02d652E8d28b61A17,223018862637142848
0x0dD3c821968FbDb6859E4b20b4B2a995F7256E2e,135070865806312752
0x1A50a6238eb67285cCD4DF17f75CCe430BAAE2A4,97328516555887712
0x5140c2e3Be04D48E9b7c5FdF016BbEA6A88B2b65,94133283238529632
0xBD8d7410467dc2EfbFfEad682DBD991b2EC23995,87531000928578480
0xa160190ACA6b3df1521F8607b4fbd07f195f09C5,79320744915981488
0xE968a888792b3c6ca4242a87445e2518F88F2e02,46016431604775048
0x23B11Ff67C2193B97cb37771D15A537B977d2278,45091628299736360
0x2B1Bfc5dCD4E21CeAA5F512e350b00c585dAE894,45089077108176856
0x1dDcd1F0C62EFD432b793c0Ac6017e7A3b970941,45079432896600056
0x5E75F78A7e50121F0aD6440651C5567c0578D9B5,44996935880306920
0x01ff0201c88E4634f8B533dDEec9902df6692345,34596713195778744
0x4Be58d08a64d455E029343F1230BBBeA992384ed,26892015704763720
0xC81f9ac9669C100Bb553cE0230Ec156ae05f820f,24716374148401936
0x8aBf9BDEBa66ce480387710a8aEDcC372625Ae0b,17996068854424782
0x1beF2b5D795E1d95ad324C6FF12053aC693097D2,11445579866792232
0x7B99c763b7B70B05a47Db32E78847c3999F671d9,11250000000000000
0xD67A3B8AF5Ec74d1E07719a6B1AfF8be5EFe68F4,9897612411792132
0x54F1b9d8F0dCF21131c0b3C1d6Bde933675C57C9,9457463562905104
0x1FA94145BF8f2C19C43Ec5CeB5C0B0dE1a31D6f5,3292720569879465
0x04fb5857bd5D98780602b84Bf03eaBDB0d3FF90B,2156705254966263

Funding request

3.1439034730360196 YFI to compensate 23 users

@austinlonestar
Copy link

When will we be refunded? Just curious

@banteg
Copy link
Author

banteg commented Sep 30, 2020

ATTN multisig overlords:

The compensation has been finalized, we need to sign two transactions:

  1. YFI.approve(Disperse, amount)
  2. Disperse.disperseToken(YFI, recipients, amounts)

To verify the calldata, please execute the following:

>>> import csv
>>> data = [(a, int(b)) for a, b in csv.reader(open('yYFI-refund.csv'))]
>>> recipients, amounts = zip(*data)
>>> amount = sum(b for a, b in data)
3143903473036019634
>>> disperse = Contract.from_explorer('0xD152f549545093347A162Dce210e7293f1452150')
>>> calldata = disperse.disperseToken.encode_input('0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e', recipients, amounts)
'0xc73a2d600000000000000000000000000bc529c00c6401aef6d220be8c6ea1667f6ad93e000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000017000000000000000000000000170ccf19d1fe9f1c360a2ef0e54983f037bb003400000000000000000000000041339d9825963515e5705df8d3b0ea98105ebb1c000000000000000000000000c10fa265ce69337eb0ecf7b02d652e8d28b61a170000000000000000000000000dd3c821968fbdb6859e4b20b4b2a995f7256e2e0000000000000000000000001a50a6238eb67285ccd4df17f75cce430baae2a40000000000000000000000005140c2e3be04d48e9b7c5fdf016bbea6a88b2b65000000000000000000000000bd8d7410467dc2efbffead682dbd991b2ec23995000000000000000000000000a160190aca6b3df1521f8607b4fbd07f195f09c5000000000000000000000000e968a888792b3c6ca4242a87445e2518f88f2e0200000000000000000000000023b11ff67c2193b97cb37771d15a537b977d22780000000000000000000000002b1bfc5dcd4e21ceaa5f512e350b00c585dae8940000000000000000000000001ddcd1f0c62efd432b793c0ac6017e7a3b9709410000000000000000000000005e75f78a7e50121f0ad6440651c5567c0578d9b500000000000000000000000001ff0201c88e4634f8b533ddeec9902df66923450000000000000000000000004be58d08a64d455e029343f1230bbbea992384ed000000000000000000000000c81f9ac9669c100bb553ce0230ec156ae05f820f0000000000000000000000008abf9bdeba66ce480387710a8aedcc372625ae0b0000000000000000000000001bef2b5d795e1d95ad324c6ff12053ac693097d20000000000000000000000007b99c763b7b70b05a47db32e78847c3999f671d9000000000000000000000000d67a3b8af5ec74d1e07719a6b1aff8be5efe68f400000000000000000000000054f1b9d8f0dcf21131c0b3c1d6bde933675c57c90000000000000000000000001fa94145bf8f2c19c43ec5ceb5c0b0de1a31d6f500000000000000000000000004fb5857bd5d98780602b84bf03eabdb0d3ff90b00000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000e62947bc8be13000000000000000000000000000000000000000000000000000e0ecc0b8066bd000000000000000000000000000000000000000000000000000318527955b2d34000000000000000000000000000000000000000000000000001dfde3c9fe3c5300000000000000000000000000000000000000000000000000159c7c527d45460000000000000000000000000000000000000000000000000014e6db8ecf94a600000000000000000000000000000000000000000000000000136f8fb492eabb00000000000000000000000000000000000000000000000000119cdcc180954b000000000000000000000000000000000000000000000000000a37bb363a2388800000000000000000000000000000000000000000000000000a03298d726552800000000000000000000000000000000000000000000000000a03046d84877d800000000000000000000000000000000000000000000000000a02781607a57f8000000000000000000000000000000000000000000000000009fdc798b2070e8000000000000000000000000000000000000000000000000007ae987006e32b8000000000000000000000000000000000000000000000000005f8a2553606d480000000000000000000000000000000000000000000000000057cf694d404b10000000000000000000000000000000000000000000000000003fef544b6be4ce0000000000000000000000000000000000000000000000000028a9b1ba3561280000000000000000000000000000000000000000000000000027f7d0bdb92000000000000000000000000000000000000000000000000000002329d377edeb04000000000000000000000000000000000000000000000000002199835424a610000000000000000000000000000000000000000000000000000bb2b63fe98ba90000000000000000000000000000000000000000000000000007a983129b83f7'
# to verify the calldata
>>> disperse.disperseToken.decode_input(calldata)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment