tenderly does not support hardhat yet.

Deploy

we can save the deployed contract address a json file.

In a config.ts we declare export const.

//config.ts
import * as dotenv from "dotenv";
dotenv.config();

export const TEST_DEPLOYER_PK = process.env.TEST_DEPLOYER_PK;
export const TEST_ETH_RPC = process.env.TEST_ETH_RPC;
export const TEST_ETH_CHAIN_ID = process.env.TEST_ETH_CHAIN_ID;
export const TEST_USDC = process.env.TEST_USDC;
export const TEST_FUND=process.env.TEST_FUND;
export const TEST_CHESS=process.env.TEST_CHESS;
export const TEST_VOTINGESCROW=process.env.TEST_VOTINGESCROW;
export const STAGING_DEPLOYER_PK = process.env.STAGING_DEPLOYER_PK;
export const STAGING_ETH_RPC = process.env.STAGING_ETH_RPC;
export const STAGING_ETH_CHAIN_ID = process.env.STAGING_ETH_CHAIN_ID;
export const STAGING_USDC= process.env.STAGING_USDC;
export const STAGING_FUND= process.env.STAGING_FUND;
export const STAGING_CHESS= process.env.STAGING_CHESS;
export const STAGING_VOTINGESCROW= process.env.STAGING_VOTINGESCROW;
import { task } from "hardhat/config";
import fs = require("fs");
import path = require("path");
import editJsonFile = require("edit-json-file");
import {
    TEST_USDC,
    TEST_FUND,
    TEST_CHESS,
    TEST_VOTINGESCROW,
    STAGING_USDC,
    STAGING_FUND,
    STAGING_CHESS,
    STAGING_VOTINGESCROW,
} from "../config";

task("deploy", "Deploy contracts", async (_args, hre) => {
    const { ethers } = hre;
    const { parseEther, parseUnits } = ethers.utils;
		// save contract address
    const CONTRACT_ADDRESS_DIR = path.join(__dirname, "..", "cache");
    if (!fs.existsSync(CONTRACT_ADDRESS_DIR)) {
        fs.mkdirSync(CONTRACT_ADDRESS_DIR);
    }
    const contractAddress = editJsonFile(path.join(CONTRACT_ADDRESS_DIR, "contract_address.json"), {
        autosave: true,
    });
    const [deployer] = await ethers.getSigners();

    await hre.run("compile");
    let usdcAddress;
    let fundAddress;
    let chessAddress;
    let votingEscrowAddress;
	// Based on the network, load different constant
    if (hre.network.name === "test") {
        usdcAddress = TEST_USDC;
        fundAddress = TEST_FUND;
        chessAddress = TEST_CHESS;
        votingEscrowAddress=TEST_VOTINGESCROW;
    } else if (hre.network.name === "staging") {
        usdcAddress = STAGING_USDC;
        fundAddress = STAGING_FUND;
        chessAddress = STAGING_CHESS;
        votingEscrowAddress=STAGING_VOTINGESCROW;
    }
	// deploy
    const Exchange = await ethers.getContractFactory("Exchange");
    const exchange = await Exchange.deploy(fundAddress,chessAddress,chessController.address,usdcAddress,
        18,
       votingEscrowAddress,
        parseUnits("0.5", 8),
        parseUnits("0.5", 8));
    contractAddress.set("test.exchange", exchange.address);
    console.log("exchange:", exchange.address);

});

Test

const { expect } = require('chai');
const { ethers } = require('hardhat');

const uniswapV2RouterAbi = require("../artifacts/contracts/PAWZToken.sol/IPancakeswapV2Router02.json").abi;
const uniswapV2PairAbi = require("../artifacts/contracts/PAWZToken.sol/IPancakeswapV2Pair.json").abi;

const uniswapV2RouterAddr = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D';
const WETHAddr = '0xc778417E063141139Fce010982780140Aa0cD5Ab';
const PONE = 10**6;
const EONE = 10**18;

describe('PAWZToken', function () {
  let signers;
  let deployer;
  let account1;
  let account2;
  let pawz;
  let uniswapV2Pair;
  let uniswapV2Router;
  
  before(async () => {
    signers = await ethers.getSigners();
    deployer = signers[0];
    const deployerAddr = await deployer.getAddress();

    pawz = await (await ethers.getContractFactory('PAWZToken')).connect(deployer).deploy();
    await pawz.deployed();

    uniswapV2Pair = await new ethers.Contract(await pawz.PancakeswapV2Pair(), uniswapV2PairAbi, deployer);

    // Add liquidity.
    uniswapV2Router = await new ethers.Contract(uniswapV2RouterAddr, uniswapV2RouterAbi, deployer);
    let amount1 = (10000 * PONE).toLocaleString('fullwide', {useGrouping:false});
    let amount2 = (10 * EONE).toLocaleString('fullwide', {useGrouping:false});
    await (await pawz.connect(deployer).approve(uniswapV2Router.address, amount1)).wait();
    await (await uniswapV2Router.connect(deployer).addLiquidityETH(pawz.address, amount1, 0, 0, deployerAddr, 9999999999, {value: amount2})).wait();

    // Send PAWZ to account1 and account2.
    let amount = (40000 * PONE).toLocaleString('fullwide', {useGrouping:false});
    account1 = signers[1];
    const account1Addr = await account1.getAddress();
    await (await pawz.connect(deployer).transfer(account1Addr, amount)).wait();

    account2 = signers[2];
    const account2Addr = await account2.getAddress();
    await (await pawz.connect(deployer).transfer(account2Addr, amount)).wait();

    // Set a lower minimumTokensBeforeSwap in order to trigger swapTokens.
    amount = (1 * PONE).toLocaleString('fullwide', {useGrouping:false});
    await (await pawz.connect(deployer).setNumTokensSellToAddToLiquidity(amount)).wait();
  });

  /*
  it('Should be ok to transfer', async function () {
    const account1Addr = await account1.getAddress();
    const account2Addr = await account2.getAddress();

    let amount = (10000 * PONE).toLocaleString('fullwide', {useGrouping:false});
    await (await pawz.connect(account1).transfer(account2Addr, amount)).wait();
    const lpBalance1 = await uniswapV2Pair.balanceOf(pawz.address);
    await (await pawz.connect(account2).transfer(account1Addr, amount)).wait();
    const lpBalance2 = await uniswapV2Pair.balanceOf(pawz.address);
    console.log('>>> LP balance: ' + lpBalance1 + ' -> ' + lpBalance2);

    expect(lpBalance2).to.above(lpBalance1);
  });
  */

  it('Should be ok to buy', async function () {
    const account1Addr = await account1.getAddress();

    await (await pawz.connect(deployer).setSwapAndLiquifyEnabled('false')).wait();

    let amount = (1 * EONE).toLocaleString('fullwide', {useGrouping:false});
    let balance1 = await pawz.balanceOf(account1Addr);
    await (await uniswapV2Router.connect(account1).swapExactETHForTokensSupportingFeeOnTransferTokens(0, [WETHAddr, pawz.address], account1Addr, 9999999999, {value: amount})).wait();
    await (await uniswapV2Router.connect(account1).swapExactETHForTokensSupportingFeeOnTransferTokens(0, [WETHAddr, pawz.address], account1Addr, 9999999999, {value: amount})).wait();
    await (await uniswapV2Router.connect(account1).swapExactETHForTokensSupportingFeeOnTransferTokens(0, [WETHAddr, pawz.address], account1Addr, 9999999999, {value: amount})).wait();
    await (await uniswapV2Router.connect(account1).swapExactETHForTokensSupportingFeeOnTransferTokens(0, [WETHAddr, pawz.address], account1Addr, 9999999999, {value: amount})).wait();
    let balance2 = await pawz.balanceOf(account1Addr);
    console.log('>>> PAWZ balance: ' + balance1 + ' -> ' + balance2);

    expect(balance2).to.above(balance1);
  });
});

Time

// Start at 12 hours after the first settlement in the next week.
        // As Fund settles at 14:00 everyday and an Unix timestamp starts a week on Thursday,
        // the test cases starts at 2:00 on Friday and the day settles at 14:00.
        let startTimestamp = (await ethers.provider.getBlock("latest")).timestamp;
        const lastDay = Math.ceil(startTimestamp / DAY / 7) * DAY * 7 + SETTLEMENT_TIME;
        const startDay = lastDay + DAY;
        startTimestamp = lastDay + 3600 * 12;
        await advanceBlockAtTime(startTimestamp);

Console

npm install --save-dev @nomiclabs/hardhat-ethers ethers
// hardhat.config.js
require('@nomiclabs/hardhat-ethers');
POC= await hre.ethers.getContractFactory("POC");
poc= await POC.attach("0x32b7c623231DD28a314473E1C8D24eccAb325Fc9");
POC= await hre.ethers.getAttractAt("POC",address);

Task

import { BigNumber } from 'ethers';
import { task } from "hardhat/config";
import editJsonFile = require("edit-json-file");
import path = require("path");

task("setTwap", "Set TWAP price")
  .addParam("price", "The price of the underlying asset.")
  .addOptionalParam("timestamp", "The time when the price happens.")
  .setAction(async (taskArgs,hre) => {
    const CONTRACT_ADDRESS_DIR = path.join(__dirname, "..", "cache");
    const contractAddress = editJsonFile(path.join(CONTRACT_ADDRESS_DIR, "contract_address.json"), {
        autosave: true,
    });
    const address = contractAddress.get("twap_oracle_BTC");
    const TwapOracle_abi = ["function setTWAP(uint256 price) external returns (uint256,uint256)"];
    // const provider = ethers.getDefaultProvider();
    const signer = (await hre.ethers.getSigners())[0];
    const TwapAbi = await hre.ethers.getContractFactory("TwapOracle");
    const TwapOracle_rw = await TwapAbi.attach(address);

    // const TwapOracle_rw = new hre.ethers.Contract(address, TwapOracle_abi, signer);
    const tx= TwapOracle_rw.setTWAP(hre.ethers.BigNumber.from(taskArgs.price));
    console.log(taskArgs.price)
    console.log(await tx)
  });