Closed valiafetisov closed 2 years ago
Here're some (ongoing) investigation records
contract name: MCD_FLAP
https://github.com/makerdao/auctions-ui/blob/master/constants.js#L39
Probably will need the following fucntions in the core for the feature:
tend
gets realised and the user can bet MKR on the auctiondeal
is realised and the user can withdraw DAI from the auctionadditional functions that might be related.
https://github.com/makerdao/auctions-ui/blob/master/hooks/useAuctionActions.js#L46-L62 https://github.com/makerdao/auctions-ui/blob/master/hooks/useAllowances.js#L86-L96
So far I did not manage to figure out how the auth should look like in the upcoming implementation but just to keep track, here's some relevant info:
(auth?) https://github.com/makerdao/auctions-ui/blob/master/hooks/useAllowances.js#L190-L204
(auth?) https://github.com/makerdao/auctions-ui/blob/master/hooks/useAllowances.js#L19
misc: provider misc: Accroding to https://github.com/makerdao/flap-auctions-api/blob/04d5250e107d7c2263968e1fec39ee38d57745f6/flap_auctions/events_extractor.py#L79-L111 we might need to react to events:
kick
ed by flap
kicks
which is the id of the latest auction or 0
bids
(public state) and passing the [id]
Kick
as in here and store parts of itTend
events:
tend
and specifying the new
(grater, it's greater by at least the minimal value of beg
, beg
is the property of the FLAP contract. https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/flap.sol#L70) price
end
is set to be now + tau
https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/flap.sol#L72 on auction starttic
is set here upon the subsequent bid =
now + ttl
https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/flap.sol#L71deal
https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/flap.sol#L157 which:
auth required
vat.hope
DaiJoin
should be set to the bid amount (probably ??? )Main source of information: latest makerdao/dss/src/flap.sol with rate limiting introduced ~3 months ago
flap
) auction, vow.flap()
have to be called with no arguments
vat.dai(vow contract address)
should be greater or equal than the sum of:
vat.sin(vow contract address)
vow.hump()
vow.bump()
vat.sin(vow contract address)
should be equal to the sum of:
vow.Sin()
vow.Ash()
flap.fill()
) should be lower or equal than the limit (flap.lid()
)flap.kick
with:vow.bump()
as lot
– DAI in return for bid0
as bid
– amount of MRK to be paidflap.bids
withbids[id].bid
– amount of MRK to be paidbids[id].lot
– amount of DAI to be receivedbids[id].guy
– the address of the wallet who made the bid (and will be able to receive DAI)bids[id].end
– final time when auction will end (now + flap.tau()
– 2 days atm)Kick
event with (id, lot, bid)
flap.kicks()
) – note that initially it's 0
flap.bids(id)
) – note that if auction is completed, there will be no data under the idflap
event called Kick
and process its parameters as in flap-auctions-apiflap.tend(id, lot, bid)
)
bids[id].tic > now || bids[id].tic == 0
and bids[id].end > now
)lot == bids[id].lot
)bid > bids[id].bid
)flap.beg()
percent, see herebids[id].bid
valuebids[id].tic
= now + flap.ttl()
, 3 hours atm)Tend
event
bids[id].tic
is 0
), the auction will expire after bids[id].end
time (currently end is set to be 2 days after auction start) and will not allow any more bids or collection of DAIflap.tick(id)
) executing which will update bids[id].end
timeis
0`)bids[id].tic
can not be 0
– meaning that there should be at least one bid (except the initial)bids[id].tic < now || bids[id].end < now
)
flap.deal(id)
should be executed by someone (not necessarily the winner), whichbids[id].guy
address (by the amount of latest lot
)bid
)delete bids[id]
)flap.fill
– total amount of currently running flap auctions
There is also a possibility to return previous bid and delete auction by calling only in case of shutdownflap.yank(id)
tend
) but doesn't seem to be required to start auction (flap
/kick
)vat.hope()
) is required to move DAI around, so I suppose it's required for every execution (TODO: check)DaiJoin
(TODO: check when and why, since no DAI suppose to be withdrawn, but MKR)Should we include functionality to start surplus auction within the UI already? I can see few pros/cons:
+
there is just one place to check it (technically we need to make at least 6 calls to check if it's possible to execute vow.flap
, few others to show other related parameters)+
it would also make sense if we would need to test it ourselves (we would only need to increase surplus in hardhat)
-
we may start testing it by running over previous version of the flap without the lid
-
to insure equal participation it will be enough to only announce started auctions via twitter and insure clear UIMy proposal is to start without kick
functionality, at least not in the UI, to limit the scope, but I would try to keep it in mind for the future.
@LukSteib, what do you think?
bids[id].end – final time when auction will end (now + flap.tau() – 2 days atm) reset expiration time to the new value (bids[id].tic = now + flap.ttl(), 3 hours atm)
I think these parameters have been updated in the past and based on https://etherscan.io/address/0xa4f79bc4a5612bdda35904fdf55fc4cb53d1bff6#readContract are currently set to
tau
== 259200 secondsttl
== 1800 secondsIn case there were no bids (ie bids[id].tic is 0), the auction will expire after bids[id].end time
I don't get the first part of this statement. How does tic (ie. the bid expiry) provide any insights on whether there have been any bids.
MKR collateral authorization is required to bid (tend) but doesn't seem to be required to start auction (flap/kick)
I don't understand the initial state after an auction has been started (flap
/ kick
), yet. If the bids.[id].bid
is 0 does it mean that one could actually make the initial tend
with a bid
of 0, since beg
applied to 0 would result in 0?! 🤯
MRK allowance (TODO: check, since we need MKR to bid, this may be required to move MRK to VAT before bidding)
question is whether MKR needs to be deposited to the VAT first in order to call tend
or if this is an atomic operation
DAI allowance to DaiJoin (TODO: check when and why, since no DAI suppose to be withdrawn, but MKR)
the winner of an auction is actually supposed to withdraw DAI from VAT, right? I am wondering whether an allowance needs to be set for DAI since we have learned in our Dai bidding flow that allowance only needs to be set for depositing of DAI but not for withdrawal.
My proposal is to start without kick functionality, at least not in the UI, to limit the scope, but I would try to keep it in mind for the future.
Agree to your proposal. Let's not include this functionality in to the UI right away.
However I like the mentioned testing scenario via hardhat (even though we might test without the recently introduced lid
parameter for now). However I am still lacking the imagination on how we will be able to manipulate hump
on hardhat fork in order to meet requirements to start flap
auction.
I think these parameters have been updated
Thanks for checking it out!
In case there were no bids (ie bids[id].tic is 0), the auction will expire after bids[id].end time
I don't get the first part of this statement. How does tic (ie. the bid expiry) provide any insights on whether there have been any bids.
Very good question. According to the code, kick
method doesn't set tic
whatsoever – so when the auction is started it will not expire quickly after 1800
seconds. Later on, they reuse same variable to check if current bid is a "real bid" or "initial kick".
does it mean that one could actually make the initial
tend
with abid
of 0
The second bid
value supplied to tend
should be greater than previous one, so it can't be equal to 0, but can be as little as 1 * 10-18 MKR.
question is whether MKR needs to be deposited to the VAT first in order to call
tend
or if this is an atomic operation
Yes, it should be deposited. The methods to move DAI and MRK around are vat.move
and gem.move
– so everything is happening within VAT.
the winner of an auction is actually supposed to withdraw DAI from VAT, right?
That's correct, but initial investigation of the transaction executed by clicking auth buttons in the existing UI lead to this conclusion. That's why there is still a todo. My speculation would be the same, we only need DAI auth, MRK auth and MRK allowance.
I am still lacking the imagination on how we will be able to manipulate
hump
on hardhat fork
Either directly changing a particular state via hardhat_setStorageAt
(see intro), or indirectly, by impersonating an account which have rights to call some auth
-protected methods, like grab
.
General ideas:
subscribeToSurplusAuctions
, and should not know internal logic (so the internal logic shuold be converted to high-level state
for example)Core surplus.ts
fetchSurplusAuctionByIndex(network, index)
(issue: #295)
// NB: this is only a proposal
interface SurplusAuctionData {
bidAmountMKR: BigNumber | undefined; // amount of MRK (bid)
receiveAmountDAI: BigNumber; // amount of DAI to be received (lot)
receiverAddress: string; // the address of the wallet who receives DAI (guy)
auctionEndDate: Date; // final date when auction will end (now + `flap.tau()` – 2 days atm) (end)
bidEndDate: Date; // (tic)
earliestEndDate: Date; // earliest of auctionEndDate and auctionEndDate
state: 'just-started' | 'have-bids' | 'ready-for-collection' | 'collected' | 'requires-restart'; // auction state determined from fetched events
}
interface SurplusBid extends SurplusAuctionData {
type: 'start' | 'bid' | 'collect'; // as 'Kick', 'Tend', 'Deal'
transactionHash: string;
transactionDate: Date; // determined from block number (see `fetchDateByBlockNumber`)
// other SurplusAuctionData fields
}
interface SurplusAuction extends SurplusAuctionData {
events: SurplusEvent[];
}
currentState === 'just-started'
, we should additionally fetch flap.kicks(index)
to check that the auction was not restarted (because calling flap.tick(index)
resets auctionEndDate
, but emits no events) – this should also be fetched after the restart transaction executionfetchCurrentSurplusAuctions(network)
(issue: #296)
index
via flap.kicks()
flap.bids()
with decreasing index
until it reaches an auction with with end === 0
fetchSurplusAuctionByIndex
for each valid index
subscribeToSurplusAuctions(network, callback)
fetchCurrentSurplusAuctions
callback(auctions)
fetchSurplusAuctionByIndex
to refetch related auction
callback([auction])
restartSurplusAuction
(tick
) (issue: #299)
subscribeToSurplusAuctions
callback to refresh restarted auctionbidToSurplusAuction
(tend
) (issue: #299)collectSurplusAuction
(deal
) (issue: #299)Frontend surplus
store (issue #300)
Record<surplusAuction.id, SurplusAuction>
setup
subscribeToSurplusAuctions
Frontend
SurplusAuction
Table SurplusAuctionsTable
(issue #302)SurplusEventsTable
(issue #303)SurplusAuctionTransactionTable
(issue #309)WalletMkrDepositCheckPanel
component in storybook (issue #310)HighestBidCheckPanel
component in storybook (issue #312)CollectSurplusAuctionPanel
component in storybook (issue #316)SurplusAuctionRestartPanels
component in storybook (#319)SurplusAuction
component and page with restart and error states (#327)SurplusAuctionTransaction
component and page with all panels #309 SurplusAuctionContainer
#340 PM
Make sure it's possible to call collateral authorization and collateral allowance functions (and also ones that fetch their statuses) with MKR as a parameter Make sure it's possible to call balance and VAT balance with MRK, deposit and withdrawal
could you elaborate on what you imply by "call with MKR", please?
Currently, we already have functions to interact with gemLike
contracts. For example withdrawCollateralFromVat
which accepts collateralType
as input. But MKR is not a "collateral type" in our internal sense and can't be added to the list of collaterals. So you either need to modify withdrawCollateralFromVat
to accept MKR (which would require a lot of refactoring and renaming) or simply copy existing logic into withdrawMRKFromVat
and modify it to work with MKR. Looking at the code, I actually think second option would make more sense.
As I needed to create the first types for the frontend issues (#306 #305) I currently updated the type mocking to:
export type SurplusAuctionStates =
| 'just-started'
| 'have-bids'
| 'ready-for-collection'
| 'collected'
| 'requires-restart';
export type SurplusAuctionEventTypes = 'start' | 'bid' | 'collect';
export declare interface SurplusAuctionData {
bidAmountMKR?: BigNumber;
receiveAmountDAI: BigNumber;
receiverAddress: string;
auctionEndDate: Date;
bidEndDate?: Date;
earliestEndDate: Date;
state: SurplusAuctionStates;
}
export declare interface SurplusEvent extends SurplusAuctionData {
type: SurplusAuctionEventTypes;
address: string;
transactionHash: string;
transactionDate: Date;
}
export declare interface InitialSurplusAuction extends SurplusAuctionData {
id: number;
network: string;
events: SurplusEvent[];
}
export declare interface SurplusAuction extends InitialSurplusAuction {
marketUnitPrice: BigNumber;
highestBid?: BigNumber;
auctionPrice?: BigNumber;
}
Regarding the block of the external code that reacts to 3 types of events:
apparently, with ethers it's not straighforward (mb even not really possible) to get the similar result.
As verbally discussed, I've looked into the possibility of getting the transactions list that is relevant to the specific contract. Due to me still not having the complete understanding of the underlying processess, i'd like to get the external input to the picture.
Discoveries
Kick
defined, i assume that the hypothetical filtering then has to only take into account the events (kick, transfer, approval)Then, according to https://github.com/makerdao/dss/blob/master/src/dai.sol (and essentially https://github.com/makerdao/dss/blob/master/src/flap.sol)
Transfer
to the contract addressTransfer
to the 0 address.Does this base idea and concept for implementation?
General context that I think is not mentioned here: contracts actually doesn't emit events on tend
and deal
, therefore proposed implementation is not directly feasible. But before significantly changing it, I suggested to check if it's still possible to subscribe to transactions instead of events and parse necessary data from them (just like it's done in the python api)
Does this base idea and concept for implementation?
I think there are two types of things: events that are explicitly emitted and transaction receipts, which can contain "events" or may not. Technically, I suppose, there should be a way to subscribe to all transactions on a specific address and parse the transaction data to determine required data (type of the method that was called, )
I would start this investigation by finding previous flap auctions and seeing what actually happening there
MCD_FLAP
address was changed (note the previous address here)The previous version emits apparently as expected kick only. The rest is nameless and apparently requires the approach of the existing python lib
i assume it might be possible to filter the transactions for specific contract
while digging i've stumbled upon the methods where every single transaction is being analysed. So at least this is possilbe via pending
filter (see this)
examples from prev versions of flapper:
Ethers.js have two different apis for event subscriptions: provider.on
and contract.on
– we wouldn't want to use the provider, otherwise we would need to parse every single mined block. It would also not allow us to fetch previous events (otherwise we would need to retrieve all blockchain blocks to find particular event). Using pending
pool is also problematic, since we only want to fetch confirmed transactions (transactions under a few other blocks), but pending
transactions are not even mined yet. Therefore, we need to use contract.on
and fetch the events not explicitly emitted, but recorded through the transaction log
.
pymaker
library first fetches events via getLogs
filtered by the contract address, then parses useful events using their signatures.
Thanks for finding previous flap contract address! Can please you try to fetch raw events from the previous flap contract using ethers.js (for now you can use hardhat to roll back to the block where this address is still in chainlog, eg 14073986), post them here and see if we can distinguish those events by the same signatures as in python library?
After a further look: previously flap contract was using note
method modifier which was responsible for logging anonymous events after tend calls as seen in the previously deployed contract code. But it's no longer the case. I am not sure if we're actually able to fetch any previous tends
or deals
Based on the investigation into the events, the conclusion is that we're not able to fetch information about previous tend
s and deal
s. We're also not able to fetch Kick
for a particular auction because its id property is not indexed therefore we can only fetch all Kicks or none. Therefore, I suggest to remove the whole possibility to get previous transactions.
I've updated the mock https://github.com/sidestream-tech/unified-auctions-ui/issues/288 based on the findings and also the previous comments left in whimsical.
Implementation proposal should be changed accordingly: we do not fetch events, remove SurplusEvent
type:
export type SurplusAuctionState =
| 'just-started'
| 'have-bids'
| 'ready-for-collection'
| 'collected'
| 'requires-restart';
export declare interface SurplusAuctionData {
id: number;
network: string;
state: SurplusAuctionState;
bidAmountMKR: BigNumber; // amount of MRK (bid)
receiveAmountDAI: BigNumber; // amount of DAI to be received (lot)
unitPrice: BigNumber; // bidAmountMKR/receiveAmountDAI or the other way around
receiverAddress: string; // the address of the wallet who receives DAI (guy)
auctionEndDate: Date; // final date when auction will end (now + `flap.tau()` – 2 days atm) (end)
bidEndDate?: Date; // (tic)
earliestEndDate: Date; // earliest of auctionEndDate and auctionEndDate
}
export declare interface SurplusAuction extends SurplusAuctionData {
marketUnitPrice: BigNumber;
// ...transaction prices
}
surplus event though contains the initial bid. That means that in order to figure out the difference between just-started
and have-bids
one has to get the initial bid. That is done via the event.
Then i assume the two states here have to be merged into one state something like live
Initial bid suppose to always be zero since kick
is called via vow.flap. But the proper way to distinguish between just-started
and have-bids
is via bidEndDate
(tic) which is not set during kick
– this is, at least, how the contract code is doing it.
According to the UniswapV2 callee code, you can call swapExactTokensForTokens
of the uniswap router (deployed at https://etherscan.io/address/0x7a250d5630b4cf539739df2c5dacb4c659f2488d on mainnet) providing:
amountIn
: amount of ETH you want to exchange (as shifted 18-symbols integer)amountOutMin
: amount of MKR you want to receive (can be 0)path
: array of addresses the exchange should take place (in our case ETH->MKR it will be ['0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2']
)to
: address of your walletdeadline
: timestamp in the futureSo you can make a small helper function exchangeEthToMkr(amount: BigNumber = new BigNumber(10))
in our code which executes this function. ETH
and MKR
addresses can be taken from the chainlog, the rest is known.
Goal
Step-by-step explanation how it works, implementation proposal
Context
Besides collateral auctions that are already supported by the UI and the keeper, we also want to support Maker surplus auctions (or
flap
auctions using maker terminology). It is currently supported by the https://auctions.makerdao.com/flap platform (source code), but our UI should eventually support all auction types. There are other projects like flap-auctions-api that may implement desired functionality in other languages that can also be used for reference.The main goal of the issue is to investigate what smart contracts are responsible for those types of auctions, how existing tools deal with it. This should be done by documenting it in the issue using english terms (instead of maker terms).
For the example of this kind of research issue, you can have a look at the recent
Implement wallet-related logic
issue https://github.com/sidestream-tech/unified-auctions-ui/issues/124 and its investigation result https://github.com/sidestream-tech/unified-auctions-ui/issues/124#issuecomment-1064277892 as well as the PR https://github.com/sidestream-tech/unified-auctions-ui/pull/143 itself.Tasks