Skip to content

Commit

Permalink
chore: add oft hts example
Browse files Browse the repository at this point in the history
Signed-off-by: nikolay <n.atanasow94@gmail.com>
  • Loading branch information
natanasow committed Dec 16, 2024
1 parent b955221 commit cf025fd
Show file tree
Hide file tree
Showing 13 changed files with 1,922 additions and 19 deletions.
10 changes: 10 additions & 0 deletions tools/layer-zero-example/.env.example
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
# keys
HEDERA_PK=0x
BSC_PK=0x

# OApp config
OAPP_HEDERA_CONTRACT=0x
OAPP_BSC_CONTRACT=0x

# OFT config
OFT_HEDERA_CONTRACT=0x
OFT_BSC_CONTRACT=0x

# OFT Adapter config
ERC20_HEDERA_CONTRACT=0x
ERC20_BSC_CONTRACT=0x
OFT_ADAPTER_HEDERA_CONTRACT=0x
OFT_ADAPTER_BSC_CONTRACT=0x

# ONFT config
ONFT_HEDERA_CONTRACT=0x
ONFT_BSC_CONTRACT=0x

# ONFT Adapter config
ERC721_HEDERA_CONTRACT=0x
ERC721_BSC_CONTRACT=0x
ONFT_ADAPTER_HEDERA_CONTRACT=0x
ONFT_ADAPTER_BSC_CONTRACT=0x

# OFT HTS config
OFT_HTS_HEDERA_CONTRACT=0x
OFT_HTS_BSC_CONTRACT=0x
24 changes: 22 additions & 2 deletions tools/layer-zero-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ npx hardhat test --grep "OAppTests @bsc @test" --network bsc_testnet

### OFT

npx hardhat deploy-oft --network hedera_testnet
npx hardhat deploy-oft --network bsc_testnet
npx hardhat deploy-oft --decimals 18 --mint 1000000000000000000 --network hedera_testnet
npx hardhat deploy-oft --decimals 18 --mint 1000000000000000000 --network bsc_testnet

npx hardhat set-peer --source <hedera_oft_address> --target <bsc_oft_address> --network hedera_testnet
npx hardhat set-peer --source <bsc_oft_address> --target <hedera_oft_address> --network bsc_testnet
Expand Down Expand Up @@ -101,5 +101,25 @@ npx hardhat test --grep "ONFTAdapterTests @bsc @approve" --network bsc_testnet
npx hardhat test --grep "ONFTAdapterTests @hedera @send" --network hedera_testnet
npx hardhat test --grep "ONFTAdapterTests @bsc @send" --network bsc_testnet

wait a couple minutes, the LZ progress can be tracked on https://testnet.layerzeroscan.com/tx/<tx_hash>

npx hardhat test --grep "ONFTAdapterTests @hedera @test" --network hedera_testnet
npx hardhat test --grep "ONFTAdapterTests @bsc @test" --network bsc_testnet

### OFT HTS

npx hardhat deploy-oft-hts --network hedera_testnet
npx hardhat deploy-oft --decimals 8 --mint 1000 --network bsc_testnet

npx hardhat set-peer --source <hedera_oft_address> --target <bsc_oft_address> --network hedera_testnet
npx hardhat set-peer --source <bsc_oft_address> --target <hedera_oft_address> --network bsc_testnet

fill the .env

npx hardhat test --grep "OFTHTSTests @hedera @send" --network hedera_testnet
npx hardhat test --grep "OFTHTSTests @bsc @send" --network bsc_testnet

wait a couple minutes, the LZ progress can be tracked on https://testnet.layerzeroscan.com/tx/<tx_hash>

npx hardhat test --grep "OFTHTSTests @hedera @test" --network hedera_testnet
npx hardhat test --grep "OFTHTSTests @bsc @test" --network bsc_testnet
45 changes: 45 additions & 0 deletions tools/layer-zero-example/contracts/BaseHTSOFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {OFTCore} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTCore.sol";

/**
* @title OFT Contract
* @dev OFT is an ERC-20 token that extends the functionality of the OFTCore contract.
*/
abstract contract BaseHTSOFT is OFTCore {
/**
* @dev Constructor for the OFT contract.
* @param _name The name of the OFT.
* @param _symbol The symbol of the OFT.
* @param _lzEndpoint The LayerZero endpoint address.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*/
constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _delegate
) OFTCore(8, _lzEndpoint, _delegate) {}

/**
* @dev Retrieves the address of the underlying ERC20 implementation.
* @return The address of the OFT token.
*
* @dev In the case of OFT, address(this) and erc20 are the same contract.
*/
function token() public view returns (address) {
return address(this);
}

/**
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
* @return requiresApproval Needs approval of the underlying token implementation.
*
* @dev In the case of OFT where the contract IS the token, approval is NOT required.
*/
function approvalRequired() external pure virtual returns (bool) {
return false;
}
}
13 changes: 11 additions & 2 deletions tools/layer-zero-example/contracts/ExampleOFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {OFT} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol";

contract ExampleOFT is OFT {
uint8 decimalsArg = 8;

constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _delegate
address _delegate,
uint256 _initialMint,
uint8 _decimals
) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {
_mint(msg.sender, 1000000000000000000);
_mint(msg.sender, _initialMint);
decimalsArg = _decimals;
}

function decimals() public view override returns (uint8) {
return decimalsArg;
}
}
97 changes: 97 additions & 0 deletions tools/layer-zero-example/contracts/ExampleOFTHTS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "./hts/HederaTokenService.sol";
import "./hts/IHederaTokenService.sol";
import "./hts/KeyHelper.sol";
import "./hts/ExpiryHelper.sol";
import "./BaseHTSOFT.sol";

contract ExampleOFTHTS is Ownable, KeyHelper, ExpiryHelper, HederaTokenService, BaseHTSOFT {
address public htsTokenAddress;

event CreatedToken(address tokenAddress);

constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _delegate
) payable BaseHTSOFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {
IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](2);
keys[0] = getSingleKey(
KeyType.ADMIN,
KeyType.PAUSE,
KeyValueType.INHERIT_ACCOUNT_KEY,
bytes("")
);
keys[1] = getSingleKey(
KeyType.SUPPLY,
KeyValueType.INHERIT_ACCOUNT_KEY,
bytes("")
);

IHederaTokenService.Expiry memory expiry = IHederaTokenService.Expiry(0, address(this), 8000000);
IHederaTokenService.HederaToken memory token = IHederaTokenService.HederaToken(
_name, _symbol, address(this), "memo", true, 1000, false, keys, expiry
);

(int responseCode, address tokenAddress) = HederaTokenService.createFungibleToken(
token, 1000, int32(int256(uint256(8)))
);
require(responseCode == HederaResponseCodes.SUCCESS, "Failed to create HTS token");

htsTokenAddress = tokenAddress;

emit CreatedToken(tokenAddress);
}

/**
* @dev Burns tokens from the sender's specified balance.
* @param _from The address to debit the tokens from.
* @param _amountLD The amount of tokens to send in local decimals.
* @param _minAmountLD The minimum amount to send in local decimals.
* @param _dstEid The destination chain ID.
* @return amountSentLD The amount sent in local decimals.
* @return amountReceivedLD The amount received in local decimals on the remote.
*/
function _debit(
address _from,
uint256 _amountLD,
uint256 _minAmountLD,
uint32 _dstEid
) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
(amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);

address spender = _msgSender();
if (_from != spender) {
int256 response = HederaTokenService.approve(htsTokenAddress, spender, amountSentLD);
require(response == HederaResponseCodes.SUCCESS, "HTS: Approve failed");
}

(int256 response,) = HederaTokenService.burnToken(htsTokenAddress, int64(uint64(amountSentLD)), new int64[](0));
require(response == HederaResponseCodes.SUCCESS, "HTS: Burn failed");
}

/**
* @dev Credits tokens to the specified address.
* @param _to The address to credit the tokens to.
* @param _amountLD The amount of tokens to credit in local decimals.
* @dev _srcEid The source chain ID.
* @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
*/
function _credit(
address _to,
uint256 _amountLD,
uint32 /*_srcEid*/
) internal virtual override returns (uint256) {
(int256 response, ,) = HederaTokenService.mintToken(htsTokenAddress, int64(uint64(_amountLD)), new bytes[](0));
require(response == HederaResponseCodes.SUCCESS, "HTS: Mint failed");

int256 transferResponse = HederaTokenService.transferToken(htsTokenAddress, address(this), _to, int64(uint64(_amountLD)));
require(transferResponse == HederaResponseCodes.SUCCESS, "HTS: Transfer failed");

return _amountLD;
}
}
21 changes: 21 additions & 0 deletions tools/layer-zero-example/contracts/hts/ExpiryHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.5.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "./HederaTokenService.sol";

abstract contract ExpiryHelper {
function createAutoRenewExpiry(
address autoRenewAccount,
int64 autoRenewPeriod
) internal pure returns (IHederaTokenService.Expiry memory expiry) {
expiry.autoRenewAccount = autoRenewAccount;
expiry.autoRenewPeriod = autoRenewPeriod;
}

function createSecondExpiry(
int64 second
) internal pure returns (IHederaTokenService.Expiry memory expiry) {
expiry.second = second;
}
}
Loading

0 comments on commit cf025fd

Please sign in to comment.