# 合约应用包说明

最近更新时间：2021-12-31 16:33:27

**应用包介绍**

合约应用包，以zip压缩包的形式存在，包含应用描述文件（metadta.xml）和solidity合约文件。

- 应用描述文件

  ```xml
  <?xml version="1.0" encoding="UTF-8"?>
  
  <metaData>
  
  ​    <name>合约名</name>
  
  ​    <symbol>contract</symbol>
  
  ​    <version>版本号</version>
  
  ​    <developer>开发者</developer>
  
  ​    <releaseDate>发布时间/releaseDate>
  
  ​    <language>语言</language>
  
  ​    <codeType>solidity</codeType>
  
  ​    <description>智能合约描述</description>
  
  ​    <size>文件大小</size>
  
  ​    <config>
  
  ​         <file>solidity文件名</file>
  
  ​          <proxy>代理合约名</proxy>
  
  ​         <proxyFile>代理合约文件名</proxyFile>
  
    </config>
  
  </metaData>
  ```

  

- 合约文件

合约文件是用Solidity语言编写的智能合约。一个应用包内可以包含多个合约文件，一般情况下只能属于同一个智能合约；如果是proxy应用包，则合约文件属于两个智能合约，一个代理合约，一个实现合约。

注意：合约名和合约文件名需要和应用描述文件的内容一致。

 

**合约应用包类型**

- 普通合约应用包

只包含普通合约，不包含管理合约和proxy合约。普通合约没有生命周期管理接口，合约升级数据会清空。

```solidity

pragma solidity ^0.6;

 

// 普通合约示例

contract MyStore {

  uint value;

  constructor() public{

​    value=9999999;

  }

 

  function set(uint x) public {

​    value = x;

  }

 

  function get() public returns (uint){

​    return value;

  }

}

 
```

- 管理合约应用包

包含普通合约和管理合约。管理合约实现合约冻结，解冻，销毁等生命周期接口和管理员的权限控制控制接口；普通合约导入管理合约，对外还是一个合约地址。

```solidity
pragma solidity > 0.6.0;

//管理合约示例
contract manage {
  // 合约部署人（超级管理员）
  address private _owner;

  // 合约管理员
  address [] private _managers;

  // 操作员
  address [] private _operators;

  // 审计人员
  address [] private _auditor;

  bool private _freezeFlag;

  constructor() public {
    _owner = msg.sender;
    _freezeFlag=false;
  }

  // 添加管理员
  function addManager(address manager) internal {
    require(msg.sender == _owner, "require owner address");
    
    _managers.push(manager);
  }

  // 删除管理员
  function removeManager(address manager) internal {
    require(msg.sender == _owner, "require owner address");

​    bool flag = false;
​    uint index = 0;
​    for(; index < _managers.length; index++) {
​      if (manager == _managers[index]) {
​        flag = true;
​        break;
​      }
​    }
​    
​    if(flag) {
​       _managers[index] = _managers[_managers.length-1];
​      _managers.pop();
​    }    
  }

  // 查询管理员
  function queryManager() internal view returns (address[] memory) {
    require(msg.sender == _owner, "require owner address");
    
    address[] memory res = new address[](_managers.length);
    for(uint i = 0; i < _managers.length; i++) {
      res[i] = _managers[i];
    }
    
    return res;
  }  

  // 检查是否管理员地址
  function checkAdminAddress(address op) internal view returns (bool) {
    if(msg.sender == _owner) return true;
    
    for(uint i = 0; i < _managers.length; i++) {
      if (op == _managers[i]) {
        return true;
      }
    }
    
    return false;
  }

  // 添加操作员
  function addOperator(address operator) public {
    bool flag = checkAdminAddress(msg.sender);
      
    require(flag, "require owner or manager address");
    
    _operators.push(operator);
  }
  
  // 删除操作员
  function removeOperator(address manager) public {
    bool flag = checkAdminAddress(msg.sender);
      
    require(flag, "require owner or manager address");
  
    flag = false;
    uint index = 0;
    for(; index < _operators.length; index++) {
      if (manager == _operators[index]) {
        flag = true;
        break;
      }
    }
    
    if(flag) {
      _operators[index] = _operators[_operators.length-1];
      _operators.pop();
    }    
  }
  
  // 查询操作员
  function queryOperator() public view returns (address[] memory) {
      bool flag = checkAdminAddress(msg.sender);
      
    require(flag, "require owner or manager address");
    
    address[] memory res = new address[](_operators.length);
    for(uint i = 0; i < _operators.length; i++) {
      res[i] = _operators[i];
    }
    
    return res;
  }
  
  // 检查是否操作员地址
  function checkOperatorAddress(address op) internal view returns (bool) {
    for(uint i = 0; i < _operators.length; i++) {
      if (op == _operators[i]) {
        return true;
      }
    }
    
    return false;
  }

  // 合约冻结
  function freeze() public returns (bool) {
    bool flag = checkAdminAddress(msg.sender);
      
    require(flag, "require owner or manager address");
    
    _freezeFlag=true;
    
    return true;
  }
  
  // 合约解冻
  function release() public returns (bool) {
    bool flag = checkAdminAddress(msg.sender);
      
    require(flag, "require owner or manager address");
    
    _freezeFlag=false;
    
    return true;
  }
  
  // 查看合约冻结状态
  function isFreeze() internal view returns (bool) {
    return _freezeFlag;
  }
  
  // 合约销毁
  function destroy() public returns (bool) {
    bool flag = checkAdminAddress(msg.sender);
      
    require(flag, "require owner or manager address");
    
    selfdestruct(payable(address(msg.sender)));
    
    return true;
  }
}

 
```



- proxy合约应用包

包含代理合约和实现合约，代理合约用于数据存储，实现合约用于逻辑操作。代理合约通过delegatecall调用实现合约。

合约升级只需要升级实现合约，代理合约地址不变。

注意：实现合约的构造函数不会生效；实现合约的变量定义需要和代理合约顺序一致。

```solidity
pragma solidity >=0.6.8 <0.9.0;

// 代理合约示例
contract proxy {
  uint value;
  address public owner;
  address internal _implementation;

  // 构造函数，参数为实现合约的地址
  constructor(address impl) public {
   owner = msg.sender;
   _implementation = impl;
  }

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

  function getOwner() public view returns (address) {
    return owner;
  }

  function implementation() public view returns (address) {
    return _implementation;
  }

  // 合约升级，参数为新合约的地址
  function upgradeTo(address impl) public onlyOwner {
    require(impl != address(0), "Cannot upgrade to invalid address");
    require(impl != _implementation, "Cannot upgrade to the same implementation");
    _implementation = impl;
  }

  // 回调函数
  fallback() external {
    address _impl = _implementation;
    require(_impl != address(0), "implementation contract not set");

​    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) }
​    }
  }
}

```



