Proxy Actions - Detailed Documentation
A generalized wrapper for the Maker Protocol
Contract Name: DssProxyActions.sol
Type/Category: Proxy Module
1. Introduction (Summary)
The Proxy Actions contract is a generalized wrapper for the Maker Protocol. It's basically a set of proxy functions for MCD (using dss-cdp-manager). The contract’s purpose is to be used via a personal ds-proxy and can be compared to the original Sag-Proxy as it offers the ability to execute a sequence of actions atomically.
2. Contract Details
Glossary (Proxy Actions)
manager - enables a formalized process for CDPs to be transferred between owners.
ilk - a collateral type.
usr - user address.
cdp - Collateralized Debt Position (now, known as Vault).
dst - refers to the destination address.
wad - quantity of tokens, usually as a fixed point integer with 10^18 decimal places.
rad - a fixed point integer, with 10^45 decimal places.
dink - change in collateral.
dart - change in debt.
ethJoin - allows native Ether to be used with the system.
gemJoin - allows standard ERC20 tokens to be deposited for use with the system.
daiJoin - allows users to withdraw their Dai from the system into a standard ERC20 token.
Key Functionalities (as defined in the smart contract)
DssProxyActions
open(): creates anUrnHandler(cdp) for the addressusr(for a specificilk) and allows the user to manage it via the internal registry of themanager.give(): transfers the ownership of thecdpto theusraddress in themanagerregistry.giveToProxy(): transfers the ownership ofcdpto the proxy ofusraddress (viaproxyRegistry) in themanagerregistry.cdpAllow(): allows/deniesusraddress to manage thecdp.urnAllow(): allows/deniesusraddress to manage themsg.senderaddress asdstforquit.flux(): moveswadamount of collateral fromcdpaddress todstaddress.move(): movesradamount of DAI fromcdpaddress todstaddress.frob(): executesfrobtocdpaddress assigning the collateral freed and/or DAI drawn to the same address.quit(): movescdpcollateral balance and debt todstaddress.enter(): movessrccollateral balance and debt tocdp.shift(): movescdpSrccollateral balance and debt tocdpDst.lockETH(): depositsmsg.valueamount of ETH inethJoinadapter and executesfrobtocdpincreasing the locked value.safeLockETH(): same thanlockETHbut requiringowner == cdp owner.lockGem(): depositswadamount of collateral ingemJoinadapter and executesfrobtocdpincreasing the locked value. Gets funds frommsg.senderiftransferFrom == true.safeLockGem(): same thanlockGembut requiringowner == cdp owner.freeETH(): executesfrobtocdpdecreasing locked collateral and withdrawswadamount of ETH fromethJoinadapter.freeGem(): executesfrobtocdpdecreasing locked collateral and withdrawswadamount of collateral fromgemJoinadapter.draw(): updates collateral fee rate, executesfrobtocdpincreasing debt and exitswadamount of DAI token (minting it) fromdaiJoinadapter.wipe(): joinswadamount of DAI token todaiJoinadapter (burning it) and executesfrobtocdpfor decreasing debt.safeWipe(): same aswipebut requiringowner == cdp owner.wipeAll(): joins all the necessary amount of DAI token todaiJoinadapter (burning it) and executesfrobtocdpsetting the debt to zero.safeWipeAll(): same aswipeAllbut requiringowner == cdp owner.lockETHAndDraw(): combineslockETHanddraw.openLockETHAndDraw(): combinesopen,lockETHanddraw.lockGemAndDraw(): combineslockGemanddraw.openLockGemAndDraw(): combinesopen,lockGemanddraw.wipeAndFreeETH(): combineswipeandfreeETH.wipeAllAndFreeETH(): combineswipeAllandfreeETH.wipeAndFreeGem(): combineswipeandfreeGem.wipeAllAndFreeGem(): combineswipeAllandfreeGem.
DssProxyActionsFlip
exitETH(): exitswadamount of ETH fromethJoinadapter. This is received in thecdpurn after the liquidation auction is over.exitGem(): exitswadamount of collateral fromgemJoinadapter. This is received in thecdpurn after the liquidation auction is over.
DssProxyActionsEnd
freeETH(): once the system is caged, this recovers the remaining ETH fromcdp(pays the remaining debt if exists).freeGem(): once the system is caged, this recovers the remaining token fromcdp(pays remaining debt if exists).pack(): once the system is caged, this packswadamount of DAI to be ready for cashing.cashETH(): once the system is caged, this casheswadamount of previously packed DAI and returns the equivalent in ETH.cashGem(): once the system is caged, this casheswadamount of previously packed DAI and returns the equivalent in gem token.
DssProxyActionsDsr
join(): joinswadamount of DAI token todaiJoinadapter (burning it) and moves the balance topotfor DAI Saving Rates.exit(): retrieveswadamount of DAI frompotand exits DAI token fromdaiJoinadapter (minting it).exitAll(): performs the same actions asexitbut for all of the available amount.
3. Key Mechanisms & Concepts
The dss-proxy-actions was designed to be used by the Ds-Proxy, which is owned individually by users to interact more easily with the Maker Protocol. Note that it is not intended to be used directly (this will be covered later). The dss-proxy-actions contract was developed to serve as a library for user's ds proxies. In general, the ds proxy receives two parameters:
Proxy library address
In this case, the dss proxy actions library
Call data
Functions and parameters you want to execute
Reference the ds-proxy for more information here.
DSProxy Summary (as it relates to the dss-proxy-actions contract)
The ds-proxy contact's purpose is to execute transactions and sequences of transactions by proxy. The contract allows code execution using a persistent identity. This can be very useful to execute a sequence of atomic actions. Since the owner of the proxy can be changed, this allows for dynamic ownership models, e.g. a multisig.
In the later example, we will see how the execute function works by using the proxy to execute calldata _data on contract _code.
The functions parameters are:
address _target
bytes memory _data
For the address-target you pass in, that will be the library you want to use, in this case the proxy actions library.
For the Memory data you pass in, that will be the call data of what exactly you want to execute.
Ex: Want to open a Vault; then the bytes memory data you will pass in will be an ABI encoder that executes open function with certain parameters.
Note: This is used for both SCD and MCD.
Proxy Action Usage Example (How a proxy call can look like)
proxy.execute(dssProxyActions, abi.encodeWithSignature("open(address,bytes32,address)", address(manager), bytes32("ETH-A"), address(0x123)))Your ds-proxy is only for you, so we create it for a wallet, so each wallet has its own ds proxy that nobody else should be able to execute with that proxy.
In MCD, the Vaults will not be owned by your wallet but by your ds proxy, which allows you to execute any function via the ds proxy. Such as performing actions within your Vaults and/or group a lot of actions within one transaction.
The execution looks something like this:
Proxy execute (call to the Ethereum blockchain) where the first parameter is the contract you are using for the library (in this case, dss proxy actions). Not that this is something the frontend will do for you. Example: When you want to open a Vault, it will send the transaction to the proxy to execute the execute function, and will then pass in the dss proxy action address and the second parameter that will be passed is the function itself that your ds proxy needs to execute from the dss proxy actions. In this case, we want to execute the open function from dss proxy action - so your proxy will delegate calling the open function from the dss proxy actions library. We need to do it this way because the second parameter is the bytes call data format parameter, so this function we ABI Encode with signature open. So, we pass the signature and then the actual parameters we want to pass to this function. In this case, the manager, the first param of the open function, the Collateral type, and the address you want to create the Vault for (In this case, the address is 0x123)
Note: UI decides which proxy action the user will use.
4. Gotchas
Using dss-proxy-actions directly can result in the loss of control over your Vault
If you open a new Vault via the dss proxy actions (centralized) without a ds proxy you would be creating a Vault that is owned by the dss proxy actions that anyone could call publicly. It would be owned by the dss proxy actions contract and anyone could execute actions on your Vault. Therefore, there is significant risk if you directly use the dss proxy actions.
When interacting with the dss-proxy-actions you need a certain allowance to get Dai or MKR funds from the user's wallet. You need allowance from your wallet to the ds-proxy (not dss-proxy-actions). Because, when you execute the dss-proxy actions, you are actually performing that action in the environment of your ds-proxy, which is delegating calls or importing the function from the proxy actions and not executing them directly.
5. Failure Modes
Ds proxy is a general purpose proxy
This means that as a user of the ds-proxy, you can execute whatever you want whether that be the Dss-proxy-actions or any other piece of code. Users are therefore responsible for what they are executing and thus, need to have trust in the UI they are using (similar to any other transaction you are executing from your wallet).
In terms of failure modes, this means you can execute a malicious proxy action as well as a direct action that could potentially send your ETH to a random address. To be extra cautious, you should check your wallets call data and/or audit what your wallet does as they could potentially present users with some unwanted random call data and execute unwanted actions.
Overall, this point is to say that there is always a risk when using a ds proxy.
Last updated