الدرس رقم 1

Managing and Upgrading Synthetic Asset Contracts

Through this lesson, you'll gain the expertise needed to manage and upgrade synthetic asset contracts, ensuring they remain adaptable to evolving requirements while maintaining the integrity and security of the contract. This foundational knowledge will be instrumental as we delve deeper into more advanced aspects of synthetic asset management in the subsequent lessons.

As we embark on this advanced segment of our course, let’s take a moment to revisit the synthetic asset contract we developed in the first part. This contract serves as the foundation upon which we will build our understanding of managing and upgrading smart contracts.

Recap of Synthetic Asset Contract

Below is the synthetic asset contract we implemented previously. This contract facilitates the creation, management, and interaction with synthetic assets on the blockchain.

Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SyntheticAsset {
    uint256 public underlyingAssetPrice;
    uint256 public collateral;
    address public owner;
    mapping(address => uint256) public syntheticBalance;
    uint256 public totalSyntheticSupply;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the contract owner");
        _;
    }

    function updatePrice(uint256 _price) public onlyOwner {
        underlyingAssetPrice = _price;
    }

    function depositCollateral(uint256 _amount) public {
        collateral += _amount;
    }

    function withdrawCollateral(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        collateral -= _amount;
    }

    function getSyntheticAssetPrice() public view returns (uint256) {
        return underlyingAssetPrice;
    }

    function mintSyntheticAsset(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        syntheticBalance[msg.sender] += _amount;
        totalSyntheticSupply += _amount;
        collateral -= _amount;
    }

    function redeemSyntheticAsset(uint256 _amount) public {
        require(syntheticBalance[msg.sender] >= _amount, "Insufficient synthetic balance");
        syntheticBalance[msg.sender] -= _amount;
        totalSyntheticSupply -= _amount;
        collateral += _amount;
    }
}

Now, with a refreshed understanding of our foundational contract, let’s delve into the aspects of managing and upgrading synthetic asset contracts.

Contract Ownership

  • Establishing contract ownership ensures that only authorized entities can modify the contract.
  • Implementing a modifier like onlyOwner to restrict access to certain functions is a common practice.

Upgrade Patterns

  • Understanding different upgrade patterns like Proxy, Eternal Storage, and DelegateCall.
  • Exploring the pros and cons of each pattern to choose the most suitable one for your contract.

Proxy Contracts

  • Delving into Proxy contracts which allow for the logic of a contract to be updated while keeping data intact.
  • Implementing a simple proxy contract to demonstrate the upgrade process.
Solidity
contract Proxy {
    address public implementation;

    function upgradeImplementation(address _newImplementation) public onlyOwner {
        implementation = _newImplementation;
    }

    fallback() external payable {
        address impl = implementation;
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }
}

Versioning

  • Implementing version control to keep track of contract upgrades.
  • Using semantic versioning to indicate the type of changes in each upgrade.

Testing Upgrades

  • Ensuring that upgrades don’t introduce bugs or alter intended functionality.
  • Testing upgrades in a controlled environment before deploying them on the mainnet.
    Below is how our system would look after incorporating a proxy contract for upgrades:
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Proxy {
    address public implementation;
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the contract owner");
        _;
    }

    function upgradeImplementation(address _newImplementation) public onlyOwner {
        implementation = _newImplementation;
    }

    fallback() external payable {
        address impl = implementation;
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }
}

contract SyntheticAsset {
    uint256 public underlyingAssetPrice;
    uint256 public collateral;
    address public owner;
    mapping(address => uint256) public syntheticBalance;
    uint256 public totalSyntheticSupply;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the contract owner");
        _;
    }

    function updatePrice(uint256 _price) public onlyOwner {
        underlyingAssetPrice = _price;
    }

    function depositCollateral(uint256 _amount) public {
        collateral += _amount;
    }

    function withdrawCollateral(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        collateral -= _amount;
    }

    function getSyntheticAssetPrice() public view returns (uint256) {
        return underlyingAssetPrice;
    }

    function mintSyntheticAsset(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        syntheticBalance[msg.sender] += _amount;
        totalSyntheticSupply += _amount;
        collateral -= _amount;
    }

    function redeemSyntheticAsset(uint256 _amount) public {
        require(syntheticBalance[msg.sender] >= _amount, "Insufficient synthetic balance");
        syntheticBalance[msg.sender] -= _amount;
        totalSyntheticSupply -= _amount;
        collateral += _amount;
    }
}

In this setup, the Proxy contract acts as a gateway for the SyntheticAsset contract, allowing for the implementation (i.e., the logic) of SyntheticAsset to be upgraded without losing the state (i.e., data) of the contract. This is achieved through the fallback function in Proxy, which delegates calls to the current implementation of SyntheticAsset, and the upgradeImplementation function, which allows the owner to change the implementation address to point to a new version of SyntheticAsset.

Through this lesson, you’ll gain the expertise needed to manage and upgrade synthetic asset contracts, ensuring they remain adaptable to evolving requirements while maintaining the integrity and security of the contract. This foundational knowledge will be instrumental as we delve deeper into more advanced aspects of synthetic asset management in the subsequent lessons. Stay tuned!

إخلاء المسؤولية
* ينطوي الاستثمار في العملات الرقمية على مخاطر كبيرة. فيرجى المتابعة بحذر. ولا تهدف الدورة التدريبية إلى تقديم المشورة الاستثمارية.
* تم إنشاء الدورة التدريبية من قبل المؤلف الذي انضم إلى مركز التعلّم في Gate. ويُرجى العلم أنّ أي رأي يشاركه المؤلف لا يمثّل مركز التعلّم في Gate.
الكتالوج
الدرس رقم 1

Managing and Upgrading Synthetic Asset Contracts

Through this lesson, you'll gain the expertise needed to manage and upgrade synthetic asset contracts, ensuring they remain adaptable to evolving requirements while maintaining the integrity and security of the contract. This foundational knowledge will be instrumental as we delve deeper into more advanced aspects of synthetic asset management in the subsequent lessons.

As we embark on this advanced segment of our course, let’s take a moment to revisit the synthetic asset contract we developed in the first part. This contract serves as the foundation upon which we will build our understanding of managing and upgrading smart contracts.

Recap of Synthetic Asset Contract

Below is the synthetic asset contract we implemented previously. This contract facilitates the creation, management, and interaction with synthetic assets on the blockchain.

Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SyntheticAsset {
    uint256 public underlyingAssetPrice;
    uint256 public collateral;
    address public owner;
    mapping(address => uint256) public syntheticBalance;
    uint256 public totalSyntheticSupply;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the contract owner");
        _;
    }

    function updatePrice(uint256 _price) public onlyOwner {
        underlyingAssetPrice = _price;
    }

    function depositCollateral(uint256 _amount) public {
        collateral += _amount;
    }

    function withdrawCollateral(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        collateral -= _amount;
    }

    function getSyntheticAssetPrice() public view returns (uint256) {
        return underlyingAssetPrice;
    }

    function mintSyntheticAsset(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        syntheticBalance[msg.sender] += _amount;
        totalSyntheticSupply += _amount;
        collateral -= _amount;
    }

    function redeemSyntheticAsset(uint256 _amount) public {
        require(syntheticBalance[msg.sender] >= _amount, "Insufficient synthetic balance");
        syntheticBalance[msg.sender] -= _amount;
        totalSyntheticSupply -= _amount;
        collateral += _amount;
    }
}

Now, with a refreshed understanding of our foundational contract, let’s delve into the aspects of managing and upgrading synthetic asset contracts.

Contract Ownership

  • Establishing contract ownership ensures that only authorized entities can modify the contract.
  • Implementing a modifier like onlyOwner to restrict access to certain functions is a common practice.

Upgrade Patterns

  • Understanding different upgrade patterns like Proxy, Eternal Storage, and DelegateCall.
  • Exploring the pros and cons of each pattern to choose the most suitable one for your contract.

Proxy Contracts

  • Delving into Proxy contracts which allow for the logic of a contract to be updated while keeping data intact.
  • Implementing a simple proxy contract to demonstrate the upgrade process.
Solidity
contract Proxy {
    address public implementation;

    function upgradeImplementation(address _newImplementation) public onlyOwner {
        implementation = _newImplementation;
    }

    fallback() external payable {
        address impl = implementation;
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }
}

Versioning

  • Implementing version control to keep track of contract upgrades.
  • Using semantic versioning to indicate the type of changes in each upgrade.

Testing Upgrades

  • Ensuring that upgrades don’t introduce bugs or alter intended functionality.
  • Testing upgrades in a controlled environment before deploying them on the mainnet.
    Below is how our system would look after incorporating a proxy contract for upgrades:
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Proxy {
    address public implementation;
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the contract owner");
        _;
    }

    function upgradeImplementation(address _newImplementation) public onlyOwner {
        implementation = _newImplementation;
    }

    fallback() external payable {
        address impl = implementation;
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }
}

contract SyntheticAsset {
    uint256 public underlyingAssetPrice;
    uint256 public collateral;
    address public owner;
    mapping(address => uint256) public syntheticBalance;
    uint256 public totalSyntheticSupply;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the contract owner");
        _;
    }

    function updatePrice(uint256 _price) public onlyOwner {
        underlyingAssetPrice = _price;
    }

    function depositCollateral(uint256 _amount) public {
        collateral += _amount;
    }

    function withdrawCollateral(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        collateral -= _amount;
    }

    function getSyntheticAssetPrice() public view returns (uint256) {
        return underlyingAssetPrice;
    }

    function mintSyntheticAsset(uint256 _amount) public {
        require(collateral >= _amount, "Insufficient collateral");
        syntheticBalance[msg.sender] += _amount;
        totalSyntheticSupply += _amount;
        collateral -= _amount;
    }

    function redeemSyntheticAsset(uint256 _amount) public {
        require(syntheticBalance[msg.sender] >= _amount, "Insufficient synthetic balance");
        syntheticBalance[msg.sender] -= _amount;
        totalSyntheticSupply -= _amount;
        collateral += _amount;
    }
}

In this setup, the Proxy contract acts as a gateway for the SyntheticAsset contract, allowing for the implementation (i.e., the logic) of SyntheticAsset to be upgraded without losing the state (i.e., data) of the contract. This is achieved through the fallback function in Proxy, which delegates calls to the current implementation of SyntheticAsset, and the upgradeImplementation function, which allows the owner to change the implementation address to point to a new version of SyntheticAsset.

Through this lesson, you’ll gain the expertise needed to manage and upgrade synthetic asset contracts, ensuring they remain adaptable to evolving requirements while maintaining the integrity and security of the contract. This foundational knowledge will be instrumental as we delve deeper into more advanced aspects of synthetic asset management in the subsequent lessons. Stay tuned!

إخلاء المسؤولية
* ينطوي الاستثمار في العملات الرقمية على مخاطر كبيرة. فيرجى المتابعة بحذر. ولا تهدف الدورة التدريبية إلى تقديم المشورة الاستثمارية.
* تم إنشاء الدورة التدريبية من قبل المؤلف الذي انضم إلى مركز التعلّم في Gate. ويُرجى العلم أنّ أي رأي يشاركه المؤلف لا يمثّل مركز التعلّم في Gate.