@ethersproject/contracts#PopulatedTransaction TypeScript Examples

The following examples show how to use @ethersproject/contracts#PopulatedTransaction. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From sdk with ISC License 7 votes vote down vote up
export function staticCallPopulatedTransaction(
    populatedTxn: Resolveable<PopulatedTransaction>,
    signer:       Signer
): Promise<StaticCallResult> {
    return Promise.resolve(populatedTxn)
        .then(txn => {
            return signer.call(txn)
                .then(()  => StaticCallResult.Success)
                .catch((err) => StaticCallResult.Failure)
        })
}
Example #2
Source File: multisig.ts    From ghst-staking with MIT License 6 votes vote down vote up
export async function sendToMultisig(
  multisigAddress: string,
  signer: Signer,
  transaction: PopulatedTransaction,
  ethers: any
) {
  const abi = [
    "function submitTransaction(address destination, uint value, bytes data) public returns (uint transactionId)",
  ];
  const multisigContract = await ethers.getContractAt(
    abi,
    multisigAddress,
    signer
  );

  console.log("tx to:", transaction.to);
  console.log("tx data:", transaction.data);

  console.log("Sending transaction to multisig:", multisigAddress);

  console.log("tx data:", transaction.data);

  let tx = await multisigContract.submitTransaction(
    transaction.to,
    0,
    transaction.data,
    { gasPrice: gasPrice }
  );
  let receipt = await tx.wait();
  if (!receipt.status) {
    throw Error(`Failed to send transaction to multisig: ${tx.hash}`);
  }
  console.log("Completed sending transaction to multisig:", tx.hash);
  return tx;
}
Example #3
Source File: utils.ts    From sdk with ISC License 6 votes vote down vote up
export function executePopulatedTransaction(
    populatedTxn: Resolveable<PopulatedTransaction>,
    signer:       Signer,
): Promise<ContractTransaction> {
    return Promise.resolve(populatedTxn)
        .then(txn => signer.sendTransaction(txn))
        .catch(rejectPromise)
}
Example #4
Source File: multisig.ts    From aavegotchi-contracts with MIT License 5 votes vote down vote up
export async function sendToMultisig(
  multisigAddress: string,
  signer: Signer,
  transaction: PopulatedTransaction,
  ethers: any
) {
  const abi = [
    "function submitTransaction(address destination, uint value, bytes data) public returns (uint transactionId)",
  ];
  const multisigContract = await ethers.getContractAt(
    abi,
    multisigAddress,
    signer
  );
  console.log("Sending transaction to multisig:", multisigAddress);

  console.log("signer:", await signer.getAddress());

  console.log("data:", transaction.data);

  //@ts-ignore
  const feeData: FeeData = await signer.provider?.getFeeData();

  console.log("feedata:", feeData);

  let tx: ContractTransaction = await multisigContract.submitTransaction(
    transaction.to,
    0,
    transaction.data,
    { gasPrice: feeData.gasPrice.mul(5).div(2) }
  );

  console.log("tx:", tx.data);

  let receipt = await tx.wait();
  if (!receipt.status) {
    throw Error(`Failed to send transaction to multisig: ${tx.hash}`);
  }
  console.log("Completed sending transaction to multisig:", tx.hash);
  return tx;
}
Example #5
Source File: multisig.ts    From ghst-staking with MIT License 5 votes vote down vote up
export async function sendToGnosisSafe(
  hre: HardhatRuntimeEnvironment,
  multisigAddress: string,
  transaction: PopulatedTransaction,
  signer: Signer
) {
  console.log(
    `Sending to Gnosis Safe at address: ${multisigAddress} on ${hre.network.name} network`
  );

  try {
    const transactions: SafeTransactionDataPartial[] = [
      {
        to: multisigAddress,
        value: transaction.value ? transaction.value.toString() : "0",
        data: transaction.data ? transaction.data : "0x",
      },
    ];

    console.log("transactions:", transactions);

    /*const ethAdapterOwner1 = new EthersAdapter({
      ethers: hre.ethers,
      signer: signer,
    });

    const chainId = await ethAdapterOwner1.getChainId();
    console.log("chain id:", chainId);

    const safeSdk: Safe = await Safe.create({
      ethAdapter: ethAdapterOwner1,
      safeAddress: multisigAddress,
      contractNetworks: {},
    });

    const safeTransaction = await safeSdk.createTransaction(...transactions);

    await safeSdk.signTransaction(safeTransaction);
    */

    console.log("Owner has signed!");
  } catch (error) {
    console.log("Error creating txn:", error);
  }
}
Example #6
Source File: refundFrens.ts    From ghst-staking with MIT License 5 votes vote down vote up
async function refundFrens() {
  let stakingFacet = await ethers.getContractAt(
    "StakingFacet",
    maticStakingAddress
  );

  if (network.name === "matic") {
    const {
      LedgerSigner,
    } = require("../../../aavegotchi-contracts/node_modules/@ethersproject/hardware-wallets");

    const signer = new LedgerSigner(ethers.provider);

    const tx: PopulatedTransaction =
      await stakingFacet.populateTransaction.adjustFrens(
        addresses,
        amounts.map((amt) => ethers.utils.parseEther(amt)),
        { gasLimit: 800000 }
      );
    await sendToMultisig(stakingDiamondUpgrader, signer, tx, ethers);
  } else {
    stakingFacet = await impersonate(
      stakingDiamondUpgrader,
      stakingFacet,
      ethers,
      network
    );

    let frens = await stakingFacet.frens(addresses[0]);
    console.log(
      `epoch frens before adjusting by ${amounts[0]}:`,
      ethers.utils.formatEther(frens)
    );

    await stakingFacet.adjustFrens(
      addresses,
      amounts.map((amt) => ethers.utils.parseEther(amt)),
      { gasPrice: gasPrice }
    );

    frens = await stakingFacet.frens(addresses[0]);
    console.log(
      "new epoch frens after adjusting:",
      ethers.utils.formatEther(frens)
    );
  }
}
Example #7
Source File: ERC20-test.ts    From sdk with ISC License 5 votes vote down vote up
describe("ERC20 tests", function(this: Mocha.Suite) {
    const testAddr: string = "0xe972647539816442e0987817DF777a9fd9878650";

    const tokenParams = (c: number): ERC20.ERC20TokenParams => ({
        chainId:      c,
        tokenAddress: Tokens.NUSD.address(c),
    })

    describe("Approval tests", function(this: Mocha.Suite) {
        interface TestCase {
            chainId: number,
            address: string,
            amount?: BigNumberish
        }

        function makeTestCase(chainId: ChainId, amount?: BigNumberish): TestCase {
            return {
                chainId,
                amount,
                address: SynapseContracts.contractsForChainId(chainId).bridgeZapAddress,
            }
        }

        let testCases: TestCase[] = [
            makeTestCase(ChainId.BSC),
            makeTestCase(ChainId.ETH),
            makeTestCase(ChainId.AVALANCHE),
            makeTestCase(ChainId.BSC,       getTestAmount(Tokens.NUSD, ChainId.BSC)),
            makeTestCase(ChainId.ETH,       getTestAmount(Tokens.NUSD, ChainId.ETH)),
            makeTestCase(ChainId.AVALANCHE, getTestAmount(Tokens.NUSD, ChainId.AVALANCHE)),
        ];

        for (const tc of testCases) {
            let {chainId, address: spender, amount} = tc;

            const args: ERC20.ApproveArgs = {spender, amount};

            it("should build a transaction successfully", async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                let prom: Promise<PopulatedTransaction> = ERC20.buildApproveTransaction(args, tokenParams(chainId));

                try {
                    return expectNull(await prom, false)
                } catch (e) {
                    return (await expectFulfilled(prom))
                }
            })
        }
    })

    describe("Balance of test", function(this: Mocha.Suite) {
        it("should have an nUSD balance greater than zero", async function(this: Mocha.Context) {
            this.timeout(DEFAULT_TEST_TIMEOUT);

            return expectNotZero(await ERC20.balanceOf(testAddr, tokenParams(ChainId.BSC)))
        })
    })

    describe("allowanceOf test", function(this: Mocha.Suite) {
        it("synapsebridgezap should have an nUSD allowance gte zero", async function(this: Mocha.Context) {
            this.timeout(DEFAULT_TEST_TIMEOUT);

            return expectGteZero(await ERC20.allowanceOf(
                testAddr,
                SynapseContracts.contractsForChainId(ChainId.BSC).bridgeZapAddress,
                tokenParams(ChainId.BSC)
            ))
        })
    })
})
Example #8
Source File: deployUpgrade.ts    From aavegotchi-contracts with MIT License 4 votes vote down vote up
task(
  "deployUpgrade",
  "Deploys a Diamond Cut, given an address, facets and addSelectors, and removeSelectors"
)
  .addParam("diamondUpgrader", "Address of the multisig signer")
  .addParam("diamondAddress", "Address of the Diamond to upgrade")
  .addParam(
    "facetsAndAddSelectors",
    "Stringified array of facet names to upgrade, along with an array of add Selectors"
  )
  .addOptionalParam("initAddress", "The facet address to call init function on")
  .addOptionalParam("initCalldata", "The calldata for init function")
  .addFlag(
    "useMultisig",
    "Set to true if multisig should be used for deploying"
  )
  .addFlag("useLedger", "Set to true if Ledger should be used for signing")
  // .addFlag("verifyFacets","Set to true if facets should be verified after deployment")

  .setAction(
    async (taskArgs: DeployUpgradeTaskArgs, hre: HardhatRuntimeEnvironment) => {
      const facets: string = taskArgs.facetsAndAddSelectors;
      const facetsAndAddSelectors: FacetsAndAddSelectors[] = convertStringToFacetAndSelectors(
        facets
      );
      const diamondUpgrader: string = taskArgs.diamondUpgrader;
      const diamondAddress: string = taskArgs.diamondAddress;
      const useMultisig = taskArgs.useMultisig;
      const useLedger = taskArgs.useLedger;
      const initAddress = taskArgs.initAddress;
      const initCalldata = taskArgs.initCalldata;

      //Instantiate the Signer
      let signer: Signer;
      const owner = await ((await hre.ethers.getContractAt(
        "OwnershipFacet",
        diamondAddress
      )) as OwnershipFacet).owner();
      const testing = ["hardhat", "localhost"].includes(hre.network.name);

      if (testing) {
        await hre.network.provider.request({
          method: "hardhat_impersonateAccount",
          params: [owner],
        });
        signer = await hre.ethers.getSigner(owner);
      } else if (hre.network.name === "matic") {
        if (useLedger) {
          signer = new LedgerSigner(hre.ethers.provider);
        } else signer = (await hre.ethers.getSigners())[0];
      } else {
        throw Error("Incorrect network selected");
      }

      //Create the cut
      const deployedFacets = [];
      const cut: Cut[] = [];

      for (let index = 0; index < facetsAndAddSelectors.length; index++) {
        const facet = facetsAndAddSelectors[index];

        console.log("facet:", facet);
        if (facet.facetName.length > 0) {
          const factory = (await hre.ethers.getContractFactory(
            facet.facetName
          )) as ContractFactory;
          const deployedFacet: Contract = await factory.deploy({
            gasPrice: gasPrice,
          });
          await deployedFacet.deployed();
          console.log(
            `Deployed Facet Address for ${facet.facetName}:`,
            deployedFacet.address
          );
          deployedFacets.push(deployedFacet);

          const newSelectors = getSighashes(facet.addSelectors, hre.ethers);

          let existingFuncs = getSelectors(deployedFacet);
          for (const selector of newSelectors) {
            if (!existingFuncs.includes(selector)) {
              const index = newSelectors.findIndex((val) => val == selector);

              throw Error(
                `Selector ${selector} (${facet.addSelectors[index]}) not found`
              );
            }
          }

          let existingSelectors = getSelectors(deployedFacet);
          existingSelectors = existingSelectors.filter(
            (selector) => !newSelectors.includes(selector)
          );
          if (newSelectors.length > 0) {
            cut.push({
              facetAddress: deployedFacet.address,
              action: FacetCutAction.Add,
              functionSelectors: newSelectors,
            });
          }

          //Always replace the existing selectors to prevent duplications
          if (existingSelectors.length > 0) {
            cut.push({
              facetAddress: deployedFacet.address,
              action: FacetCutAction.Replace,
              functionSelectors: existingSelectors,
            });
          }
        }
        let removeSelectors: string[];
        if (taskArgs.rawSigs == true) {
          removeSelectors = facet.removeSelectors;
        } else {
          removeSelectors = getSighashes(facet.removeSelectors, hre.ethers);
        }
        if (removeSelectors.length > 0) {
          console.log("Removing selectors:", removeSelectors);
          cut.push({
            facetAddress: hre.ethers.constants.AddressZero,
            action: FacetCutAction.Remove,
            functionSelectors: removeSelectors,
          });
        }
      }

      //Execute the Cut
      const diamondCut = (await hre.ethers.getContractAt(
        "IDiamondCut",
        diamondAddress,
        signer
      )) as IDiamondCut;

      //Helpful for debugging
      const diamondLoupe = (await hre.ethers.getContractAt(
        "IDiamondLoupe",
        diamondAddress,
        signer
      )) as IDiamondLoupe;

      if (testing) {
        console.log("Diamond cut");
        const tx: ContractTransaction = await diamondCut.diamondCut(
          cut,
          initAddress ? initAddress : hre.ethers.constants.AddressZero,
          initCalldata ? initCalldata : "0x",
          { gasLimit: 8000000 }
        );
        console.log("Diamond cut tx:", tx.hash);
        const receipt: ContractReceipt = await tx.wait();
        if (!receipt.status) {
          throw Error(`Diamond upgrade failed: ${tx.hash}`);
        }
        console.log("Completed diamond cut: ", tx.hash);
      } else {
        //Choose to use a multisig or a simple deploy address
        if (useMultisig) {
          console.log("Diamond cut");
          const tx: PopulatedTransaction = await diamondCut.populateTransaction.diamondCut(
            cut,
            initAddress ? initAddress : hre.ethers.constants.AddressZero,
            initCalldata ? initCalldata : "0x",
            { gasLimit: 800000 }
          );
          await sendToMultisig(diamondUpgrader, signer, tx, hre.ethers);
        } else {
          const tx: ContractTransaction = await diamondCut.diamondCut(
            cut,
            initAddress ? initAddress : hre.ethers.constants.AddressZero,
            initCalldata ? initCalldata : "0x",
            { gasLimit: 800000 }
          );

          const receipt: ContractReceipt = await tx.wait();
          if (!receipt.status) {
            throw Error(`Diamond upgrade failed: ${tx.hash}`);
          }
          console.log("Completed diamond cut: ", tx.hash);
        }
      }
    }
  );
Example #9
Source File: deployUpgrade.ts    From ghst-staking with MIT License 4 votes vote down vote up
task(
  "deployUpgrade",
  "Deploys a Diamond Cut, given an address, facets and addSelectors, and removeSelectors"
)
  .addParam("diamondUpgrader", "Address of the multisig signer")
  .addParam("diamondAddress", "Address of the Diamond to upgrade")
  .addParam(
    "facetsAndAddSelectors",
    "Stringified array of facet names to upgrade, along with an array of add Selectors"
  )
  .addOptionalParam("initAddress", "The facet address to call init function on")
  .addOptionalParam("initCalldata", "The calldata for init function")
  .addFlag(
    "useMultisig",
    "Set to true if multisig should be used for deploying"
  )
  .addFlag("useLedger", "Set to true if Ledger should be used for signing")
  // .addFlag("verifyFacets","Set to true if facets should be verified after deployment")

  .setAction(
    async (taskArgs: DeployUpgradeTaskArgs, hre: HardhatRuntimeEnvironment) => {
      const facets: string = taskArgs.facetsAndAddSelectors;
      const facetsAndAddSelectors: FacetsAndAddSelectors[] =
        convertStringToFacetAndSelectors(facets);
      const diamondUpgrader: string = taskArgs.diamondUpgrader;
      const diamondAddress: string = taskArgs.diamondAddress;
      const useMultisig = taskArgs.useMultisig;
      const useLedger = taskArgs.useLedger;
      const initAddress = taskArgs.initAddress;
      const initCalldata = taskArgs.initCalldata;

      //Instantiate the Signer
      let signer: Signer;
      const owner = await (
        (await hre.ethers.getContractAt(
          "OwnershipFacet",
          diamondAddress
        )) as OwnershipFacet
      ).owner();
      const testing = ["hardhat", "localhost"].includes(hre.network.name);

      if (testing) {
        await hre.network.provider.request({
          method: "hardhat_impersonateAccount",
          params: [owner],
        });
        signer = await hre.ethers.getSigner(owner);
      } else if (hre.network.name === "matic") {
        if (useLedger) {
          signer = new LedgerSigner(hre.ethers.provider);
        } else signer = (await hre.ethers.getSigners())[0];
      } else {
        throw Error("Incorrect network selected");
      }

      //Create the cut
      const deployedFacets = [];
      const cut: Cut[] = [];

      for (let index = 0; index < facetsAndAddSelectors.length; index++) {
        const facet = facetsAndAddSelectors[index];

        const factory = (await hre.ethers.getContractFactory(
          facet.facetName
        )) as ContractFactory;
        const deployedFacet: Contract = await factory.deploy({
          gasPrice: gasPrice,
        });
        await deployedFacet.deployed();
        console.log(
          `Deployed Facet Address for ${facet.facetName}:`,
          deployedFacet.address
        );
        deployedFacets.push(deployedFacet);

        //Verify
        if (hre.network.name === "matic") {
          // await hre.run("verify:verify", {
          //   address: deployedFacet.address,
          //   constructorArguments: [],
          // });
        }

        const newSelectors = getSighashes(facet.addSelectors, hre.ethers);

        const removeSelectors = getSighashes(facet.removeSelectors, hre.ethers);

        let existingFuncs = getSelectors(deployedFacet);

        console.log("existing funcs:", existingFuncs);
        for (const selector of newSelectors) {
          if (!existingFuncs.includes(selector)) {
            const index = newSelectors.findIndex((val) => val == selector);

            throw Error(
              `Selector ${selector} (${facet.addSelectors[index]}) not found`
            );
          }
        }

        // console.log("funcs:", existingFuncs.length);

        let existingSelectors = getSelectors(deployedFacet);
        existingSelectors = existingSelectors.filter(
          (selector) => !newSelectors.includes(selector)
        );

        // console.log("existing selectors:", existingSelectors);

        // console.log("funcs:", existingSelectors.length);

        if (newSelectors.length > 0) {
          cut.push({
            facetAddress: deployedFacet.address,
            action: FacetCutAction.Add,
            functionSelectors: newSelectors,
          });
        }

        //Always replace the existing selectors to prevent duplications

        //remove extra selectors

        // existingSelectors = existingSelectors.filter(
        //   (selector) => !extra.includes(selector)
        // );

        if (existingSelectors.length > 0)
          cut.push({
            facetAddress: deployedFacet.address,
            action: FacetCutAction.Replace,
            functionSelectors: existingSelectors,
          });

        if (removeSelectors.length > 0) {
          cut.push({
            facetAddress: hre.ethers.constants.AddressZero,
            action: FacetCutAction.Remove,
            functionSelectors: removeSelectors,
          });
        }
      }

      console.log(cut);

      //Execute the Cut
      const diamondCut = (await hre.ethers.getContractAt(
        "IDiamondCut",
        diamondAddress,
        signer
      )) as IDiamondCut;

      if (testing) {
        console.log("Diamond cut");
        const tx: ContractTransaction = await diamondCut.diamondCut(
          cut,
          initAddress ? initAddress : hre.ethers.constants.AddressZero,
          initCalldata ? initCalldata : "0x",
          { gasLimit: 8000000 }
        );
        console.log("Diamond cut tx:", tx.hash);
        const receipt: ContractReceipt = await tx.wait();
        if (!receipt.status) {
          throw Error(`Diamond upgrade failed: ${tx.hash}`);
        }
        console.log("Completed diamond cut: ", tx.hash);
      } else {
        //Choose to use a multisig or a simple deploy address
        if (useMultisig) {
          console.log("Diamond cut");
          const tx: PopulatedTransaction =
            await diamondCut.populateTransaction.diamondCut(
              cut,
              initAddress ? initAddress : hre.ethers.constants.AddressZero,
              initCalldata ? initCalldata : "0x",
              { gasLimit: 800000 }
            );
          await sendToMultisig(diamondUpgrader, signer, tx, hre.ethers);
        } else {
          const tx: ContractTransaction = await diamondCut.diamondCut(
            cut,
            initAddress ? initAddress : hre.ethers.constants.AddressZero,
            initCalldata ? initCalldata : "0x",
            { gasLimit: 800000, gasPrice: gasPrice }
          );

          const receipt: ContractReceipt = await tx.wait();
          if (!receipt.status) {
            throw Error(`Diamond upgrade failed: ${tx.hash}`);
          }
          console.log("Completed diamond cut: ", tx.hash);
        }
      }
    }
  );
Example #10
Source File: ProviderInteractions-test.ts    From sdk with ISC License 4 votes vote down vote up
describe("SynapseBridge - Provider Interactions tests", async function(this: Mocha.Suite) {

    interface TestOpts {
        executeSuccess: boolean,
        canBridge:      boolean,
    }

    interface TestCase extends BridgeSwapTestCase<TestOpts> {
        callStatic: boolean,
    }

    const executeFailAmt: BigNumber = parseEther("420.696969");

    const testCases: TestCase[] = [
        {
            args: {
                tokenFrom:   Tokens.ETH,
                tokenTo:     Tokens.WETH,
                chainIdFrom: ChainId.OPTIMISM,
                chainIdTo:   ChainId.ETH,
                amountFrom:  executeFailAmt,
            },
            expected: {
                executeSuccess: false,
                canBridge:      false,
            },
            callStatic:         false,
        },
        {
            args: {
                tokenFrom:   Tokens.ETH,
                tokenTo:     Tokens.WETH,
                chainIdFrom: ChainId.BOBA,
                chainIdTo:   ChainId.ETH,
                amountFrom:  executeFailAmt,
            },
            expected: {
                executeSuccess: false,
                canBridge:      false,
            },
            callStatic:         true,
        },
        {
            args: {
                tokenFrom:   Tokens.ETH,
                tokenTo:     Tokens.WETH_E,
                chainIdFrom: ChainId.ARBITRUM,
                chainIdTo:   ChainId.AVALANCHE,
                amountFrom:  parseEther("0.005"),
            },
            expected: {
                executeSuccess: true,
                canBridge:      true,
            },
            callStatic:         true,
        },
        // {
        //     args: {
        //         tokenFrom:   Tokens.WETH_E,
        //         tokenTo:     Tokens.ETH,
        //         chainIdFrom: ChainId.AVALANCHE,
        //         chainIdTo:   ChainId.ARBITRUM,
        //         amountFrom:  parseEther("0.05"),
        //     },
        //     expected: {
        //         executeSuccess: false,
        //         canBridge:      false,
        //     },
        //     callStatic:         true,
        // },
        {
            args: {
                tokenFrom:   Tokens.ETH,
                tokenTo:     Tokens.NETH,
                chainIdFrom: ChainId.ETH,
                chainIdTo:   ChainId.OPTIMISM,
                amountFrom:  executeFailAmt,
            },
            expected: {
                executeSuccess: false,
                canBridge:      false,
            },
            callStatic:         true,
        },
        {
            args: {
                tokenFrom:   Tokens.ETH,
                tokenTo:     Tokens.NETH,
                chainIdFrom: ChainId.ETH,
                chainIdTo:   ChainId.OPTIMISM,
                amountFrom:  executeFailAmt,
            },
            expected: {
                executeSuccess: false,
                canBridge:      false,
            },
            callStatic:         false,
        },
        {
            args: {
                tokenFrom:   Tokens.NUSD,
                tokenTo:     Tokens.USDT,
                chainIdFrom: ChainId.POLYGON,
                chainIdTo:   ChainId.FANTOM,
                amountFrom:  parseEther("666"),
            },
            expected: {
                executeSuccess: false,
                canBridge:      false,
            },
            callStatic:         false,
        },
    ];

    const getBridgeEstimate = async (
        tc: TestCase,
        {
            address,
            bridgeInstance,
        }: WalletArgs
    ): Promise<EstimateOutputs> =>
        bridgeInstance.estimateBridgeTokenOutput(tc.args)
            .then(res =>
                ({
                    outputEstimate: res,
                    bridgeArgs: {
                        ...tc.args,
                        amountTo: res.amountToReceive,
                        addressTo: address,
                    }
                })
            )
            .catch(rejectPromise)

    testCases.forEach(tc => {
        const
            describeNetFromTitle: string = `${tc.args.tokenFrom.symbol} on ${Networks.networkName(tc.args.chainIdFrom)}`,
            desribeNetToTitle:    string = `${tc.args.tokenTo.symbol} on ${Networks.networkName(tc.args.chainIdTo)}`,
            execModeTitle:        string = tc.callStatic ? "(CallStatic)" : "(Signer Sends)",
            describeTitle:        string = `Test ${describeNetFromTitle} to ${desribeNetToTitle} ${execModeTitle}`,
            executionTestSuffix:  string = `should ${tc.expected.executeSuccess ? "execute succesfully" : "fail"}`;

        const
            executeTxnTestTitle = (txnKind: string): string => `${txnKind} transaction ${executionTestSuffix}`,
            approvalTxnTestTitle: string = executeTxnTestTitle("ERC20.Approve"),
            bridgeTxnTestTitle:   string = executeTxnTestTitle("SynapseBridge token bridge");

        describe(describeTitle, function(this: Mocha.Suite) {
            let
                walletArgs:     WalletArgs,
                wallet:         Wallet,
                bridgeInstance: Bridge.SynapseBridge;

            before(async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                walletArgs = await buildWalletArgs(
                    tc.args.chainIdFrom,
                    bridgeInteractionsPrivkey.privkey
                );

                wallet         = walletArgs.wallet;
                bridgeInstance = walletArgs.bridgeInstance;
            })

            function executeTxnFunc(
                tc:       TestCase,
                prom:     Promise<TxnResponse>,
                approval: boolean=false
            ): (ctx: Mocha.Context) => PromiseLike<any> {
                return async function (ctx: Mocha.Context): Promise<void | any> {
                    if (approval && tc.args.tokenFrom.isEqual(Tokens.ETH)) return

                    ctx.timeout(20*1000);

                    let execProm = executeTransaction(prom);

                    return (await (tc.expected.executeSuccess
                            ? expectFulfilled(execProm)
                            : expectRejected(execProm)
                    ))
                }
            }

            function callStaticFunc(
                tc:       TestCase,
                prom:     Promise<StaticCallResult>,
                approval: boolean=false
            ): (ctx: Mocha.Context) => PromiseLike<any> {
                return async function (ctx: Mocha.Context): Promise<void | any> {
                    if (approval && tc.args.tokenFrom.isEqual(Tokens.ETH)) return

                    ctx.timeout(5*1000);

                    let execProm = callStatic(prom);

                    return (await (tc.expected.executeSuccess
                            ? expectFulfilled(execProm)
                            : expectRejected(execProm)
                    ))
                }
            }

            let
                outputEstimate: Bridge.BridgeOutputEstimate,
                doBridgeArgs:   Bridge.BridgeTransactionParams;

            step("acquire output estimate", async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                let prom = getBridgeEstimate(tc, walletArgs);

                await expectFulfilled(prom);

                const {outputEstimate: estimate, bridgeArgs: bridgeParams} = await prom;

                expectNotZero(estimate.amountToReceive);

                outputEstimate = estimate;
                doBridgeArgs = bridgeParams;

                return
            });

            describe("- checkCanBridge()", function(this: Mocha.Suite) {
                const canBridgeTestTitle: string = `should${tc.expected.canBridge ? "" : " not"} be able to bridge`;

                it(canBridgeTestTitle, function(this: Mocha.Context, done: Mocha.Done) {
                    this.timeout(3.5*1000);
                    this.slow(2*1000);

                    let prom = bridgeInstance.checkCanBridge({
                        token: tc.args.tokenFrom,
                        signer: wallet,
                        amount: tc.args.amountFrom,
                    }).then(({canBridge}) => canBridge)

                    expect(prom).to.eventually.equal(tc.expected.canBridge).notify(done);
                })
            });

            describe("- Transaction Builders", function(this: Mocha.Suite) {
                let
                    approvalTxn:     PopulatedTransaction,
                    bridgeTxn:       PopulatedTransaction;

                const
                    approveTitle: string = "approval transaction should be populated successfully",
                    bridgeTitle:  string = "bridge transaction should be populated successfully";

                step(approveTitle, async function(this: Mocha.Context) {
                    if (tc.args.tokenFrom.isEqual(Tokens.ETH)) return
                    this.timeout(DEFAULT_TEST_TIMEOUT);

                    return (await expectFulfilled(
                        bridgeInstance
                            .buildApproveTransaction({token: tc.args.tokenFrom})
                            .then((txn) => approvalTxn = txn)
                    ))
                });

                step(bridgeTitle, async function(this: Mocha.Context) {
                    this.timeout(DEFAULT_TEST_TIMEOUT);

                    return (await expectFulfilled(
                        bridgeInstance.buildBridgeTokenTransaction(doBridgeArgs)
                            .then((txn) => bridgeTxn = txn)
                    ))
                });

                const approval = true;

                step(approvalTxnTestTitle, async function(this: Mocha.Context) {
                    if (tc.callStatic) {
                        return await callStaticFunc(
                            tc,
                            staticCallPopulatedTransaction(approvalTxn, wallet),
                            approval
                        )(this)
                    } else {
                        return await executeTxnFunc(
                            tc,
                            wallet.sendTransaction(approvalTxn),
                            approval
                        )(this)
                    }
                });

                step(bridgeTxnTestTitle, async function(this: Mocha.Context) {
                    if (tc.callStatic) {
                        return await callStaticFunc(
                            tc,
                            staticCallPopulatedTransaction(bridgeTxn, wallet)
                        )(this)
                    } else {
                        return await executeTxnFunc(
                            tc,
                            wallet.sendTransaction(bridgeTxn)
                        )(this)
                    }
                });
            });

            (tc.callStatic ? describe.skip : describe)("- Magic Executors", function(this: Mocha.Suite) {
                const approval = true;

                step(approvalTxnTestTitle, async function(this: Mocha.Context) {
                    return await executeTxnFunc(
                        tc,
                        bridgeInstance.executeApproveTransaction({token: tc.args.tokenFrom}, wallet),
                        approval
                    )(this)
                });

                step(bridgeTxnTestTitle, async function (this: Mocha.Context) {
                    return await executeTxnFunc(
                        tc,
                        bridgeInstance.executeBridgeTokenTransaction(doBridgeArgs, wallet)
                    )(this)
                });
            })
        })
    })
})
Example #11
Source File: buildBridgeTokenTransaction-test.ts    From sdk with ISC License 4 votes vote down vote up
describe("SynapseBridge - buildBridgeTokenTransaction tests", function(this: Mocha.Suite) {
    interface Expected {
        wantFn: string,
    }

    type TestCase = BridgeSwapTestCase<Expected>

    const makeTestCase = (
        t1: Token, t2: Token,
        c1: number, c2: number,
        wantFn:    string,
    ): TestCase => {
        const expected: Expected = {wantFn};

        return makeBridgeSwapTestCase(c1, t1, c2, t2, expected, getTestAmount(t1, c1))
    }

    function makeTestName(tc: TestCase): string {
        let {
            args: {
                amountFrom,
                tokenFrom,
                tokenFrom: { symbol: tokFrom },
                tokenTo:   { symbol: tokTo   },
                chainIdFrom: chainFrom,
                chainIdTo:   chainTo,
            },
            expected: {wantFn}
        } = tc;

        const
            amt             = formatUnits(amountFrom, tokenFrom.decimals(chainFrom)),
            netFrom         = Networks.networkName(chainFrom),
            netTo           = Networks.networkName(chainTo);

        const
            testPrefix:      string = "buildBridgeTokenTransaction()",
            testParamsTitle: string = `with params ${tokFrom} on ${netFrom} -> ${tokTo} on ${netTo}`,
            testWant:        string = `should be a transaction which calls ${wantFn}()`;

        return `${testPrefix} ${testParamsTitle} ${testWant}`
    }

    const
        redeem                  = "redeem",
        deposit                 = "deposit",
        depositETH              = "depositETH",
        redeemAndSwap           = "redeemAndSwap",
        redeemAndRemove         = "redeemAndRemove",
        swapAndRedeemAndRemove  = "swapAndRedeemAndRemove",
        swapETHAndRedeem        = "swapETHAndRedeem",
        swapAndRedeem           = "swapAndRedeem",
        swapETHAndRedeemAndSwap = "swapETHAndRedeemAndSwap",
        swapAndRedeemAndSwap    = "swapAndRedeemAndSwap",
        zapAndDeposit           = "zapAndDeposit",
        zapAndDepositAndSwap    = "zapAndDepositAndSwap",
        depositAndSwap          = "depositAndSwap",
        depositETHAndSwap       = "depositETHAndSwap";

    [
        makeTestCase(Tokens.DAI,       Tokens.USDC,      ChainId.ETH,       ChainId.BSC,         zapAndDepositAndSwap),
        makeTestCase(Tokens.NETH,      Tokens.ETH,       ChainId.BOBA,      ChainId.ETH,         redeem),
        makeTestCase(Tokens.NETH,      Tokens.NETH,      ChainId.BOBA,      ChainId.ETH,         redeem),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.BOBA,      ChainId.BSC,         swapAndRedeem),
        makeTestCase(Tokens.USDC,      Tokens.USDT,      ChainId.BSC,       ChainId.BOBA,        swapAndRedeemAndSwap),
        makeTestCase(Tokens.FRAX,      Tokens.FRAX,      ChainId.MOONRIVER, ChainId.ETH,         redeem),
        makeTestCase(Tokens.FRAX,      Tokens.FRAX,      ChainId.ETH,       ChainId.MOONRIVER,   deposit),
        makeTestCase(Tokens.SYN,       Tokens.SYN,       ChainId.MOONRIVER, ChainId.ETH,         redeem),
        makeTestCase(Tokens.SYN,       Tokens.SYN,       ChainId.ETH,       ChainId.MOONRIVER,   redeem),
        makeTestCase(Tokens.ETH,       Tokens.NETH,      ChainId.OPTIMISM,  ChainId.ETH,         swapETHAndRedeem),
        makeTestCase(Tokens.ETH,       Tokens.NETH,      ChainId.ETH,       ChainId.AVALANCHE,   depositETH),
        makeTestCase(Tokens.WETH_E,    Tokens.ETH,       ChainId.AVALANCHE, ChainId.ETH,         swapAndRedeem),
        makeTestCase(Tokens.WETH_E,    Tokens.ETH,       ChainId.AVALANCHE, ChainId.ARBITRUM,    swapAndRedeemAndSwap),
        makeTestCase(Tokens.ETH,       Tokens.WETH_E,    ChainId.ETH,       ChainId.AVALANCHE,   depositETHAndSwap),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.AVALANCHE, ChainId.ETH,         redeemAndRemove),
        makeTestCase(Tokens.DAI,       Tokens.DAI,       ChainId.AVALANCHE, ChainId.ETH,         swapAndRedeemAndRemove),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.AVALANCHE, ChainId.POLYGON,     redeemAndSwap),
        makeTestCase(Tokens.DOG,       Tokens.DOG,       ChainId.POLYGON,   ChainId.ETH,         redeem),
        makeTestCase(Tokens.ETH,       Tokens.ETH,       ChainId.ARBITRUM,  ChainId.OPTIMISM,    swapETHAndRedeemAndSwap),
        makeTestCase(Tokens.NETH,      Tokens.ETH,       ChainId.ARBITRUM,  ChainId.OPTIMISM,    redeemAndSwap),
        makeTestCase(Tokens.JUMP,      Tokens.JUMP,      ChainId.FANTOM,    ChainId.BSC,         deposit),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.AVALANCHE, ChainId.OPTIMISM,    redeem),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.ETH,       ChainId.AVALANCHE,   deposit),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.HARMONY,   ChainId.MOONRIVER,   redeem),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.ETH,       ChainId.AVALANCHE,   deposit),
        makeTestCase(Tokens.USDC,      Tokens.USDC,      ChainId.AURORA,    ChainId.AVALANCHE,   swapAndRedeemAndSwap),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.BSC,       ChainId.AURORA,      swapAndRedeem),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.AURORA,    ChainId.ETH,         swapAndRedeem),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.ETH,       ChainId.AURORA,      zapAndDeposit),
        makeTestCase(Tokens.WETH,      Tokens.WETH_E,    ChainId.ETH,       ChainId.AVALANCHE,   depositETHAndSwap),
        makeTestCase(Tokens.NUSD,      Tokens.NUSD,      ChainId.ETH,       ChainId.AVALANCHE,   deposit),
        makeTestCase(Tokens.WETH_E,    Tokens.WETH,      ChainId.AVALANCHE, ChainId.OPTIMISM,    swapAndRedeemAndSwap),
        makeTestCase(Tokens.WETH,      Tokens.ONE_ETH,   ChainId.ETH,       ChainId.HARMONY,     depositETHAndSwap),
        makeTestCase(Tokens.ONE_ETH,   Tokens.WETH_E,    ChainId.HARMONY,   ChainId.AVALANCHE,   swapAndRedeemAndSwap),
        makeTestCase(Tokens.HIGH,      Tokens.HIGH,      ChainId.BSC,       ChainId.ETH,         redeem),
        makeTestCase(Tokens.JUMP,      Tokens.JUMP,      ChainId.BSC,       ChainId.FANTOM,      redeem),
        makeTestCase(Tokens.DOG,       Tokens.DOG,       ChainId.BSC,       ChainId.POLYGON,     redeem),
        makeTestCase(Tokens.NFD,       Tokens.NFD,       ChainId.POLYGON,   ChainId.AVALANCHE,   deposit),
        makeTestCase(Tokens.GMX,       Tokens.GMX,       ChainId.ARBITRUM,  ChainId.AVALANCHE,   deposit),
        makeTestCase(Tokens.GMX,       Tokens.GMX,       ChainId.AVALANCHE, ChainId.ARBITRUM,    redeem),
        makeTestCase(Tokens.SOLAR,     Tokens.SOLAR,     ChainId.MOONRIVER, ChainId.MOONBEAM,    deposit),
        makeTestCase(Tokens.WAVAX,     Tokens.AVAX,      ChainId.MOONBEAM,  ChainId.AVALANCHE,   redeem),
        makeTestCase(Tokens.AVAX,      Tokens.WAVAX,     ChainId.AVALANCHE, ChainId.MOONBEAM,    depositETH),
        makeTestCase(Tokens.WMOVR,     Tokens.MOVR,      ChainId.MOONBEAM,  ChainId.MOONRIVER,   redeem),
        makeTestCase(Tokens.MOVR,      Tokens.WMOVR,     ChainId.MOONRIVER, ChainId.MOONBEAM,    depositETH),
        makeTestCase(Tokens.FTM_ETH,   Tokens.WETH,      ChainId.FANTOM,    ChainId.ETH,         swapAndRedeem),
        makeTestCase(Tokens.FTM_ETH,   Tokens.ETH,       ChainId.FANTOM,    ChainId.ETH,         swapAndRedeem),
        makeTestCase(Tokens.FTM_ETH,   Tokens.WETH_E,    ChainId.FANTOM,    ChainId.AVALANCHE,   swapAndRedeemAndSwap),
        makeTestCase(Tokens.WETH_E,    Tokens.FTM_ETH,   ChainId.AVALANCHE, ChainId.FANTOM,      swapAndRedeemAndSwap),
        makeTestCase(Tokens.ETH,       Tokens.FTM_ETH,   ChainId.ETH,       ChainId.FANTOM,      depositETHAndSwap),
        makeTestCase(Tokens.WETH,      Tokens.FTM_ETH,   ChainId.ETH,       ChainId.FANTOM,      depositETHAndSwap),
        makeTestCase(Tokens.ETH,       Tokens.WETH_E,    ChainId.ARBITRUM,  ChainId.AVALANCHE,   swapETHAndRedeemAndSwap),
        makeTestCase(Tokens.WETH,      Tokens.WETH_E,    ChainId.ARBITRUM,  ChainId.AVALANCHE,   swapETHAndRedeemAndSwap),
        makeTestCase(Tokens.WETH_E,    Tokens.ETH,       ChainId.AVALANCHE, ChainId.ARBITRUM,    swapAndRedeemAndSwap),
        makeTestCase(Tokens.WETH_E,    Tokens.WETH,      ChainId.AVALANCHE, ChainId.ARBITRUM,    swapAndRedeemAndSwap),
        makeTestCase(Tokens.USDC,      Tokens.DAI,       ChainId.BSC,       ChainId.ETH,         swapAndRedeemAndRemove),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.BSC,       ChainId.ETH,         redeemAndRemove),
        makeTestCase(Tokens.NUSD,      Tokens.USDC,      ChainId.ETH,       ChainId.BSC,         depositAndSwap),
        makeTestCase(Tokens.NUSD,      Tokens.NUSD,      ChainId.BSC,       ChainId.POLYGON,     redeem),
        makeTestCase(Tokens.NUSD,      Tokens.NUSD,      ChainId.POLYGON,   ChainId.BSC,         redeem),
        makeTestCase(Tokens.UST,       Tokens.UST,       ChainId.BSC,       ChainId.POLYGON,     redeem),
        makeTestCase(Tokens.UST,       Tokens.UST,       ChainId.POLYGON,   ChainId.ETH,         redeem),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ARBITRUM,  ChainId.AVALANCHE,   redeem),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ETH,       ChainId.AVALANCHE,   deposit),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.AVALANCHE, ChainId.ETH,         redeem),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.ETH,       ChainId.FANTOM,      deposit),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.AVALANCHE, ChainId.HARMONY,     redeem),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.FANTOM,    ChainId.HARMONY,     redeem),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.AVALANCHE, ChainId.FANTOM,      redeem),
        makeTestCase(Tokens.LUNA,      Tokens.LUNA,      ChainId.ARBITRUM,  ChainId.OPTIMISM,    redeem),
        makeTestCase(Tokens.LUNA,      Tokens.LUNA,      ChainId.OPTIMISM,  ChainId.ARBITRUM,    redeem),
        makeTestCase(Tokens.METIS_ETH, Tokens.WETH_E,    ChainId.METIS,     ChainId.AVALANCHE,   swapAndRedeemAndSwap),
        makeTestCase(Tokens.ETH,       Tokens.METIS_ETH, ChainId.ETH,       ChainId.METIS,       depositETHAndSwap),
        makeTestCase(Tokens.NETH,      Tokens.WETH_E,    ChainId.METIS,     ChainId.AVALANCHE,   redeemAndSwap),
    ].forEach((tc: TestCase) => {
        const testTitle = makeTestName(tc);
        describe(testTitle, function(this: Mocha.Suite) {
            let builtTxn: PopulatedTransaction;

            const amountTo = tc.args.amountFrom.sub(5);

            step("build transaction", async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                let {args: { chainIdFrom }, args} = tc;

                const
                    bridgeInstance    = new Bridge.SynapseBridge({ network: chainIdFrom }),
                    addressTo: string = makeWalletSignerWithProvider(chainIdFrom, bridgeTestPrivkey1).address;

                let prom = bridgeInstance.buildBridgeTokenTransaction({...args, amountTo, addressTo});
                Promise.resolve(prom).then(built => builtTxn = built);

                return (await expectFulfilled(prom))
            })

            let txnInfo: TransactionDescription;
            const
                l1BridgeZapInterface = L1BridgeZapFactory.createInterface(),
                l2BridgeZapInterface = L2BridgeZapFactory.createInterface();


            step(`tx should be a call to function ${tc.expected.wantFn}()`, function(this: Mocha.Context) {
                txnInfo = tc.args.chainIdFrom === ChainId.ETH
                    ? l1BridgeZapInterface.parseTransaction({data: builtTxn.data || ""})
                    : l2BridgeZapInterface.parseTransaction({data: builtTxn.data || ""});

                expect(txnInfo.name).to.equal(tc.expected.wantFn);
            });
        });
    });
});