1. 引言
在Solidity合约中动态部署合约的方案有:
- 1)Wormhole 1.0 中的
deployWrappedAsset
:https://github.com/certusone/wormhole/blob/v1.3.0/ethereum/contracts/Wormhole.sol#L212 - 2)Optics Bridge中的
_deployToken
:https://github.com/celo-org/optics-monorepo/blob/main/solidity/optics-xapps/contracts/bridge/TokenRegistry.sol#L174
2. Wormhole 1.0中的deployWrappedAsset
需先部署相应的WrappedAsset合约。参考https://github.com/OpenZeppelin/openzeppelin-sdk/blob/master/packages/lib/contracts/upgradeability/ProxyFactory.sol。
前序博客有:
详细代码为:
function deployWrappedAsset(bytes32 seed, uint8 token_chain, bytes32 token_address, uint8 decimals) private returns (address asset){
// Taken from https://github.com/OpenZeppelin/openzeppelin-sdk/blob/master/packages/lib/contracts/upgradeability/ProxyFactory.sol
// Licensed under MIT
bytes20 targetBytes = bytes20(wrappedAssetMaster);
assembly {
let clone := mload(0x40)
mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(clone, 0x14), targetBytes)
mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
asset := create2(0, clone, 0x37, seed)
}
// Call initializer
WrappedAsset(asset).initialize(token_chain, token_address, decimals);
// Store address
wrappedAssets[seed] = asset;
isWrappedAsset[asset] = true;
}
在Wormhole 2.0中,部署Wrapped合约的方式不再由合约部署,改为外部调用部署:
function createWrapped(bytes memory encodedVm) external returns (address token) {
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
require(valid, reason);
require(verifyBridgeVM(vm), "invalid emitter");
BridgeStructs.AssetMeta memory meta = parseAssetMeta(vm.payload);
return _createWrapped(meta, vm.sequence);
}
// Creates a wrapped asset using AssetMeta
function _createWrapped(BridgeStructs.AssetMeta memory meta, uint64 sequence) internal returns (address token) {
require(meta.tokenChain != chainId(), "can only wrap tokens from foreign chains");
require(wrappedAsset(meta.tokenChain, meta.tokenAddress) == address(0), "wrapped asset already exists");
// initialize the TokenImplementation
bytes memory initialisationArgs = abi.encodeWithSelector(
TokenImplementation.initialize.selector,
bytes32ToString(meta.name),
bytes32ToString(meta.symbol),
meta.decimals,
sequence,
address(this),
meta.tokenChain,
meta.tokenAddress
);
// initialize the BeaconProxy
bytes memory constructorArgs = abi.encode(address(this), initialisationArgs);
// deployment code
bytes memory bytecode = abi.encodePacked(type(BridgeToken).creationCode, constructorArgs);
bytes32 salt = keccak256(abi.encodePacked(meta.tokenChain, meta.tokenAddress));
assembly {
token := create2(0, add(bytecode, 0x20), mload(bytecode), salt)//部署合约
if iszero(extcodesize(token)) {
revert(0, 0)
}
}
setWrappedAsset(meta.tokenChain, meta.tokenAddress, token);
}
function setWrappedAsset(uint16 tokenChainId, bytes32 tokenAddress, address wrapper) internal {
_state.wrappedAssets[tokenChainId][tokenAddress] = wrapper;
_state.isWrappedAsset[wrapper] = true;
}
3. Optics Bridge中的_deployToken
需先部署相应的BridgeToken合约。实际部署依赖可参看:tokenBeacon依赖关系
前序博客有:
详细代码为:
/**
* @notice Deploy and initialize a new token contract
* @dev Each token contract is a proxy which
* points to the token upgrade beacon
* @return _token the address of the token contract
*/
function _deployToken(bytes29 _tokenId) internal returns (address _token) {
// deploy and initialize the token contract
_token = address(new UpgradeBeaconProxy(tokenBeacon, ""));
// initialize the token separately from the
IBridgeToken(_token).initialize();
// set the default token name & symbol
string memory _name;
string memory _symbol;
(_name, _symbol) = _defaultDetails(_tokenId);
IBridgeToken(_token).setDetails(_name, _symbol, 18);
// store token in mappings
representationToCanonical[_token].domain = _tokenId.domain();
representationToCanonical[_token].id = _tokenId.id();
canonicalToRepresentation[_tokenId.keccak()] = _token;
// emit event upon deploying new token
emit TokenDeployed(_tokenId.domain(), _tokenId.id(), _token);
}
合约部署合约交易示例为:【对比https://etherscan.io/tx/0x43a0836d748ccdc431a2ef63f0fbb51eeb201114db605eb19d8c693809395900 仅proveAndProcess的gas为188K,而 部署token合约+proveAndProcess的gas为633K。所以部署token合约的gas约为445K。】
部署的token的地址为:
从Optics BridgeRouter合约中读取:
https://etherscan.io/address/0x4fc16De11deAc71E8b2Db539d82d93BE4b486892#readProxyContract
从https://explorer.celo.org/address/0x74c0C58B99b68cF16A717279AC2d056A34ba2bFe/contracts 可知,部署的该token对应为Celo链上的Source token。