Solidity

如何僅使用合約而不是 Dapp 前端從 DSR(Oasis Saving Dapp / MakerDao)中提取 DAI?

  • April 9, 2022

我目前正在測試 MakerDao 的 Oasis Saving Dapp ( https://oasis.app/save )。將部分 DAI 轉換為 DSR 後,使用者可以節省資金,並隨時使用 Dapp 前端提款按鈕提取資金(轉換回 DAI)。

我喜歡這個想法,但在發送更多 DAI 之前,我想弄清楚如何在不使用前端的情況下與合約進行互動。

**有人可以告訴我如何僅使用契約程式碼提取所有儲蓄嗎?**所以不使用 Oasis 前端。我想知道我需要呼叫哪些函式以及要填充什麼作為輸入。

這是部署在儲戶賬戶上的合約程式碼:

pragma solidity ^0.4.23;

contract DSAuthority {
   function canCall(
       address src, address dst, bytes4 sig
   ) public view returns (bool);
}

contract DSAuthEvents {
   event LogSetAuthority (address indexed authority);
   event LogSetOwner     (address indexed owner);
}

contract DSAuth is DSAuthEvents {
   DSAuthority  public  authority;
   address      public  owner;

   constructor() public {
       owner = msg.sender;
       emit LogSetOwner(msg.sender);
   }

   function setOwner(address owner_)
       public
       auth
   {
       owner = owner_;
       emit LogSetOwner(owner);
   }

   function setAuthority(DSAuthority authority_)
       public
       auth
   {
       authority = authority_;
       emit LogSetAuthority(authority);
   }

   modifier auth {
       require(isAuthorized(msg.sender, msg.sig));
       _;
   }

   function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
       if (src == address(this)) {
           return true;
       } else if (src == owner) {
           return true;
       } else if (authority == DSAuthority(0)) {
           return false;
       } else {
           return authority.canCall(src, this, sig);
       }
   }
}

contract DSNote {
   event LogNote(
       bytes4   indexed  sig,
       address  indexed  guy,
       bytes32  indexed  foo,
       bytes32  indexed  bar,
       uint              wad,
       bytes             fax
   ) anonymous;

   modifier note {
       bytes32 foo;
       bytes32 bar;

       assembly {
           foo := calldataload(4)
           bar := calldataload(36)
       }

       emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);

       _;
   }
}

// DSProxy
// Allows code execution using a persistant 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
// i.e. a multisig
contract DSProxy is DSAuth, DSNote {
   DSProxyCache public cache;  // global cache for contracts

   constructor(address _cacheAddr) public {
       require(setCache(_cacheAddr));
   }

   function() public payable {
   }

   // use the proxy to execute calldata _data on contract _code
   function execute(bytes _code, bytes _data)
       public
       payable
       returns (address target, bytes32 response)
   {
       target = cache.read(_code);
       if (target == 0x0) {
           // deploy contract & store its address in cache
           target = cache.write(_code);
       }

       response = execute(target, _data);
   }

   function execute(address _target, bytes _data)
       public
       auth
       note
       payable
       returns (bytes32 response)
   {
       require(_target != 0x0);

       // call contract in current context
       assembly {
           let succeeded := delegatecall(sub(gas, 5000), _target, add(_data, 0x20), mload(_data), 0, 32)
           response := mload(0)      // load delegatecall output
           switch iszero(succeeded)
           case 1 {
               // throw if delegatecall failed
               revert(0, 0)
           }
       }
   }

   //set new cache
   function setCache(address _cacheAddr)
       public
       auth
       note
       returns (bool)
   {
       require(_cacheAddr != 0x0);        // invalid cache address
       cache = DSProxyCache(_cacheAddr);  // overwrite cache
       return true;
   }
}

// DSProxyFactory
// This factory deploys new proxy instances through build()
// Deployed proxy addresses are logged
contract DSProxyFactory {
   event Created(address indexed sender, address indexed owner, address proxy, address cache);
   mapping(address=>bool) public isProxy;
   DSProxyCache public cache = new DSProxyCache();

   // deploys a new proxy instance
   // sets owner of proxy to caller
   function build() public returns (DSProxy proxy) {
       proxy = build(msg.sender);
   }

   // deploys a new proxy instance
   // sets custom owner of proxy
   function build(address owner) public returns (DSProxy proxy) {
       proxy = new DSProxy(cache);
       emit Created(msg.sender, owner, address(proxy), address(cache));
       proxy.setOwner(owner);
       isProxy[proxy] = true;
   }
}

// DSProxyCache
// This global cache stores addresses of contracts previously deployed
// by a proxy. This saves gas from repeat deployment of the same
// contracts and eliminates blockchain bloat.

// By default, all proxies deployed from the same factory store
// contracts in the same cache. The cache a proxy instance uses can be
// changed.  The cache uses the sha3 hash of a contract's bytecode to
// lookup the address
contract DSProxyCache {
   mapping(bytes32 => address) cache;

   function read(bytes _code) public view returns (address) {
       bytes32 hash = keccak256(_code);
       return cache[hash];
   }

   function write(bytes _code) public returns (address target) {
       assembly {
           target := create(0, add(_code, 0x20), mload(_code))
           switch iszero(extcodesize(target))
           case 1 {
               // throw if contract failed to deploy
               revert(0, 0)
           }
       }
       bytes32 hash = keccak256(_code);
       cache[hash] = target;
   }
}

來源:https ://etherscan.io/address/0xad01c274961a55a493991e1f63e0c362aabf6705#code

點擊 Dapp 上的撤消按鈕時,似乎execute()呼叫了該函式,但我不明白什麼是bytes _data. Metamask 為這個參數顯示了一個很長的輸入(228 字節),但我不明白它的含義以及如何在需要時自己猜測它。有人知道要準確呼叫什麼以及要填寫什麼作為輸入嗎?

作為一個去中心化的應用程序,如果由於某種原因前端不可用(維護、更新……)並且有人想要他的資金回來,這將非常有用。

謝謝 :)

但我不明白是什麼bytes _data

這是一個編碼的函式呼叫,在 function 內部執行(通過彙編)execute

以下是編碼函式呼叫的範例:

bytes4 selector = bytes4(uint256(keccak256("someFunc(address,uint256,bool)") >> 224));
bytes memory data = abi.encodeWithSelector(selector, someAddress, someUint256, someBool);

當然,上面的編碼是在鏈上(合約內部)執行的,而您需要在鏈下(例如,在 web3.js 腳本中)計算相同的東西,然後將其傳遞給合約的功能。

萬一綠洲網站消失了怎麼辦?我的代幣是否因為被委派了一份困難的契約而面臨風險?

這就是為什麼我也想知道如何僅使用契約程式碼提取我的儲蓄。

從上面的答案看起來很複雜,我不知道如何生成該數據欄位。也許有人可以對MEW合約互動進行逐步描述以退出綠洲DSR合約嗎?

引用自:https://ethereum.stackexchange.com/questions/79529