Skip to content

Instantly share code, notes, and snippets.

@sunnyRK
Last active June 5, 2023 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sunnyRK/609aeee596c83424204e8f2b13ceebfc to your computer and use it in GitHub Desktop.
Save sunnyRK/609aeee596c83424204e8f2b13ceebfc to your computer and use it in GitHub Desktop.
async function setUpMainentContracts(signer) {
[LZEndpointMockFactory, usdcMainnetInstnace, HGTRemoteFactory, HGTFactory] =
await Promise.all([
new ethers.ContractFactory(
LZEndpointMock.abi,
LZEndpointMock.bytecode,
signer
),
new ethers.Contract(usdcMainnet, IERC20.abi, signer),
ethers.getContractFactory("HGTRemote", signer),
ethers.getContractFactory("HGT", signer),
]);
lzEndpointMockFrom = await LZEndpointMockFactory.deploy(toChainId); // from CChain
lzEndpointMockTo = await LZEndpointMockFactory.deploy(secondToChainId); // to HubbleNet with dummy ChainId
hgtRemote = await HGTRemoteFactory.deploy(
signer._address,
signer._address,
lzEndpointMockFrom.address,
usdcMainnet
);
hgt = await HGTFactory.deploy(lzEndpointMockTo.address);
await lzEndpointMockFrom.setDestLzEndpoint(
hgt.address,
lzEndpointMockTo.address
);
await lzEndpointMockTo.setDestLzEndpoint(
hgtRemote.address,
lzEndpointMockFrom.address
);
await hgtRemote.setTrustedRemote(
secondToChainId,
ethers.utils.solidityPack(
["address", "address"],
[hgt.address, hgtRemote.address]
)
);
await hgt.setTrustedRemote(
toChainId,
ethers.utils.solidityPack(
["address", "address"],
[hgtRemote.address, hgt.address]
)
);
await signer.sendTransaction({
to: hgtRemote.address,
value: ethers.utils.parseEther("2.0"), // Sends exactly 1.0 ether
});
await signer.sendTransaction({
to: hgt.address,
value: ethers.utils.parseEther("2.0"), // Sends exactly 1.0 ether
});
// console.log('lzEndpointMockFrom: ', lzEndpointMockFrom.address);
// console.log('lzEndpointMockTo: ', lzEndpointMockTo.address);
// console.log('usdcMainnetInstnace: ', usdcMainnetInstnace.address);
// console.log('hgtRemote: ', hgtRemote.address);
// console.log('hgt: ', hgt.address);
// console.log('signer: ', signer._address);
const res = {
lzEndpointMockFrom,
lzEndpointMockTo,
usdcMainnetInstnace,
hgtRemote,
hgt,
};
return res;
}
function forkMainet(_network, blockNumber) {
return network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
},
},
],
});
}
function depositBySocket(
uint16 _dstChainId,
bytes memory _toAddress,
uint _amount,
address payable _refundAddress,
address _zroPaymentAddress,
bytes memory _adapterParams
) external checkWhiteList payable {
_send(
_msgSender(), _dstChainId, _toAddress, _amount, _refundAddress,
_zroPaymentAddress, _adapterParams, msg.value, // msg.value
false
);
}
Error: Transaction reverted without a reason string
at <UnrecognizedContract>.<unknown> (0x33be2a7cf4bb94d28131116f840d313cab1ed2da)
at <UnrecognizedContract>.<unknown> (0xc30141b657f4216252dc59af2e7cdb9d8792e1b0)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at EthModule._estimateGasAction (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:425:7)
at HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:117:18)
at EthersProviderWrapper.send (node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
const request = require("request");
const {BigNumber} = require("ethers");
const API_KEY = "645b2c8c-5825-4930-baf3-d9b997fcd88c";
const {ethers} = require("hardhat");
async function doRequest(url) {
return new Promise(function (resolve, reject) {
request(url, function (error, res, body) {
if (!error && res.statusCode == 200) {
resolve(JSON.parse(body));
} else {
reject(error);
}
});
});
}
// Makes a GET request to Socket APIs for quote
async function getQuote(
fromChainID,
fromTokenAddress,
toChainId,
toTokenAddress,
fromAmount,
userAddress,
recipient,
destinationPayload,
estimation
) {
const quoteApi =
"https://api.socket.tech/v2/quote" +
`?fromChainId=${fromChainID}` +
`&fromTokenAddress=${fromTokenAddress}` +
`&toChainId=${toChainId}` +
`&toTokenAddress=${toTokenAddress}` +
`&fromAmount=${fromAmount}` +
`&userAddress=${userAddress}` +
`&recipient=${recipient}` +
"&uniqueRoutesPerBridge=true" +
"&includeBridges=" +
"&sort=output" +
"&singleTxOnly=true" +
`&destinationPayload=${destinationPayload}` +
`&destinationGasLimit=${estimation}`;
const response = await fetch(quoteApi, {
method: "GET",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
});
const json = await response.json();
return json;
}
// Makes a POST request to Socket APIs for swap/bridge transaction data
async function postBuildTx(route, destinationCallData) {
const response = await fetch("https://api.socket.tech/v2/build-tx", {
method: "POST",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
route: route,
destinationCallData: destinationCallData,
}),
});
const json = await response.json();
return json;
}
async function getBuildTx(
sender,
recipient,
routePath,
fromChainId,
toChainId,
routeId,
fromTokenAddress,
toTokenAddress,
fromAmount,
toAmount,
destinationPayload,
destinationGasLimit,
bridgeInputTokenAddress
) {
const buildTx =
"https://api.socket.tech/v2/build-tx" +
`?sender=${sender}` +
`&recipient=${recipient}` +
`&routePath=${routePath}` +
`&fromChainId=${fromChainId}` +
`&toChainId=${toChainId}` +
`&routeId=${routeId}` +
`&fromTokenAddress=${fromTokenAddress}` +
`&toTokenAddress=${toTokenAddress}` +
`&fromAmount=${fromAmount}` +
`&toAmount=${toAmount}` +
`&destinationPayload=${destinationPayload}` +
`&destinationGasLimit=${destinationGasLimit}` +
`&bridgeInputTokenAddress=${bridgeInputTokenAddress}`;
const response = await fetch(buildTx, {
method: "GET",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
});
const json = await response.json();
return json;
}
// Makes a POST request to Socket APIs for swap/bridge transaction data
async function postRouteStart(
route,
destinationCallData,
fromAssetAddress,
toAssetAddress
) {
const response = await fetch("https://api.socket.tech/v2/route/start", {
method: "POST",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
fromChainId: 1,
toChainId: 43114,
fromAssetAddress: fromAssetAddress,
toAssetAddress: toAssetAddress,
includeFirstTxDetails: true,
destinationCallData: destinationCallData,
route: route,
}),
});
const json = await response.json();
return json;
}
// GET request to check token allowance given to allowanceTarget by owner
async function buildNextTx(activeRouteId) {
const response = await fetch(
`https://api.socket.tech/v2/route/build-next-tx?activeRouteId=${activeRouteId}`,
{
method: "GET",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
}
);
const json = await response.json();
return json;
}
// GET request to check token allowance given to allowanceTarget by owner
async function checkAllowance(chainId, owner, allowanceTarget, tokenAddress) {
const response = await fetch(
`https://api.socket.tech/v2/approval/check-allowance?chainID=${chainId}&owner=${owner}&allowanceTarget=${allowanceTarget}&tokenAddress=${tokenAddress}`,
{
method: "GET",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
}
);
const json = await response.json();
return json;
}
// Fetches transaction data for token approval
async function getApprovalTransactionData(
chainId,
owner,
allowanceTarget,
tokenAddress,
amount
) {
const response = await fetch(
`https://api.socket.tech/v2/approval/build-tx?chainID=${chainId}&owner=${owner}&allowanceTarget=${allowanceTarget}&tokenAddress=${tokenAddress}&amount=${amount}`,
{
method: "GET",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
}
);
const json = await response.json();
return json;
}
// Fetches status of the bridging transaction
async function getBridgeStatus(transactionHash, fromChainId, toChainId) {
const response = await fetch(
`https://api.socket.tech/v2/bridge-status?transactionHash=${transactionHash}&fromChainId=${fromChainId}&toChainId=${toChainId}`,
{
method: "GET",
headers: {
"API-KEY": API_KEY,
Accept: "application/json",
"Content-Type": "application/json",
},
}
);
const json = await response.json();
return json;
}
async function getGasValue(estimate) {
const increaseEstimated = BigNumber.from(estimate).add("30000"); // + 30k
const currentGasPrice = await ethers.provider.getGasPrice();
const inGwei = ethers.utils.formatUnits(currentGasPrice, "gwei");
const priceInValue = BigNumber.from(increaseEstimated).mul(currentGasPrice);
// console.log('priceInValue', priceInValue.toString())
return priceInValue;
}
module.exports = {
doRequest,
getQuote,
postBuildTx,
getBuildTx,
postRouteStart,
checkAllowance,
getBridgeStatus,
getApprovalTransactionData,
getGasValue,
buildNextTx,
};
const {expect} = require("chai");
const {ethers} = require("hardhat");
const {BigNumber} = require("ethers");
const {parseEther} = require("ethers/lib/utils");
const {
getQuote,
checkAllowance,
getApprovalTransactionData,
getGasValue,
getBuildTx,
} = require("./socketUtils");
const utils = require("./utils");
const {
constants: {_1e6},
setUpMainentContracts,
} = utils;
const USDCRichAddressAvax = "0x9f8c163cBA728e99993ABe7495F06c0A3c8Ac8b9";
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
const usdcMainnet = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const usdcAvax = "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E";
const USDCRichAddress = "0x79E2Ba942B0e8fDB6ff3d406e930289d10B49ADe"; // for impersonate
const fromChainId = 1;
const toChainId = 43114;
const secondToChainId = 2;
const fromAmount = "1000000";
const dummyGasFees = parseEther("0.1"); // in eth terms
const eventTopics =
"0x28fd8a5dda29b4035905e0657f97244a0e0bef97951e248ed0f2c6878d6590c2"; // event ExecutionCompleted() from socket
describe("SocketRouter Tests", async function () {
before(async function () {
signers = await ethers.getSigners();
[alice] = signers.map((s) => s.address);
await utils.forkMainet();
await utils.impersonateAccount(USDCRichAddress);
adminSigner = await ethers.provider.getSigner(USDCRichAddress);
contracts = await setUpMainentContracts(adminSigner);
({
lzEndpointMockFrom,
lzEndpointMockTo,
usdcMainnetInstnace,
hgtRemote,
hgt,
} = contracts);
});
it.only("Reverted, Not Valid Relayer", async () => {
const toAddress = ethers.utils.solidityPack(["address"], [alice]);
await expect(
hgtRemote
.connect(signers[0])
.depositBySocket(
secondToChainId,
toAddress,
fromAmount,
hgtRemote.address,
ZERO_ADDRESS,
"0x",
{
value: dummyGasFees,
}
)
).to.be.revertedWith("Not Valid Relayer");
});
// ChainId 1 -> 43114
it.only("Hop1 Chain1(1) -> Chain2(43114)", async () => {
const toAddress = ethers.utils.solidityPack(["address"], [alice]);
const fees = await hgt.estimateSendFee(
toChainId,
toAddress,
fromAmount,
false,
"0x"
);
let estimation = await hgtRemote.estimateGas.depositBySocket(
secondToChainId,
toAddress,
fromAmount,
hgtRemote.address,
ZERO_ADDRESS,
"0x",
{
value: fees[0], // need to fix this
}
);
estimation = BigNumber.from(estimation).add(30000).toString();
const txData = await hgtRemote.populateTransaction.depositBySocket(
secondToChainId,
toAddress,
fromAmount,
hgtRemote.address,
ZERO_ADDRESS,
"0x",
{
value: fees[0],
}
);
const quoteResponse = await getQuote(
fromChainId,
usdcMainnet,
toChainId,
usdcAvax,
fromAmount,
adminSigner._address,
hgtRemote.address,
txData.data,
estimation
// txData.gasLimit.toString()
);
// GET Api
const apiReturnData = await getBuildTx(
adminSigner._address,
hgtRemote.address,
quoteResponse.result.routes[0].userTxs[0].routePath,
fromChainId,
toChainId,
quoteResponse.result.routes[0].routeId,
usdcMainnet,
usdcAvax,
quoteResponse.result.routes[0].fromAmount,
quoteResponse.result.routes[0].toAmount,
quoteResponse.result.destinationCallData.destinationPayload,
quoteResponse.result.destinationCallData.destinationGasLimit,
usdcMainnet
);
const usdcBalBefore = await usdcMainnetInstnace.balanceOf(
adminSigner._address
);
// approval
const approvalData = apiReturnData.result.approvalData;
const {allowanceTarget, minimumApprovalAmount} = approvalData;
if (approvalData !== null) {
// Fetches token allowance given to Socket contracts
const allowanceCheckStatus = await checkAllowance(
fromChainId,
adminSigner._address,
allowanceTarget,
usdcMainnet
);
const allowanceValue = allowanceCheckStatus.result?.value;
if (minimumApprovalAmount > allowanceValue) {
const approvalTransactionData =
await getApprovalTransactionData(
fromChainId,
adminSigner._address,
allowanceTarget,
usdcMainnet,
fromAmount
);
const gasPrice = await adminSigner.getGasPrice();
const gasEstimate = await ethers.provider.estimateGas({
from: adminSigner._address,
to: approvalTransactionData.result?.to,
value: "0x00",
data: approvalTransactionData.result?.data,
gasPrice: gasPrice,
});
const tx = await adminSigner.sendTransaction({
from: approvalTransactionData.result?.from,
to: approvalTransactionData.result?.to,
value: "0x00",
data: approvalTransactionData.result?.data,
gasPrice: gasPrice,
gasLimit: gasEstimate,
});
const receipt = await tx.wait();
}
}
const gasPrice = await adminSigner.getGasPrice();
const gasEstimate = await ethers.provider.estimateGas({
from: adminSigner._address,
to: apiReturnData.result.txTarget,
value: apiReturnData.result.value,
data: apiReturnData.result.txData,
gasPrice: gasPrice,
});
const tx = await adminSigner.sendTransaction({
from: adminSigner._address,
to: apiReturnData.result.txTarget,
data: apiReturnData.result.txData,
value: apiReturnData.result.value,
gasPrice: gasPrice,
gasLimit: gasEstimate,
});
const receipt = await tx.wait();
const usdcBalAfter = await usdcMainnetInstnace.balanceOf(
adminSigner._address
);
expect(receipt.logs[0].topics[0]).to.eq(eventTopics); // check is event emit from socket
expect(BigNumber.from(usdcBalAfter)).to.eq(
BigNumber.from(usdcBalBefore).sub(fromAmount)
);
});
// ChainId 43114 -> 2(Dummy ChainId for Hubblnett)
it.only("Hop2 Chain2(43114) -> Chain3(2)", async () => {
await usdcMainnetInstnace.transfer(
hgtRemote.address,
BigNumber.from("1000000")
);
const toAddress = ethers.utils.solidityPack(["address"], [alice]);
const fees = await hgt.estimateSendFee(
toChainId,
toAddress,
fromAmount,
false,
"0x"
);
const hgtBalanceBefore = await ethers.provider.getBalance(hgt.address);
const adminBalanceBefore = await ethers.provider.getBalance(alice);
await expect(
hgtRemote.depositBySocket(
secondToChainId,
toAddress,
fromAmount,
hgtRemote.address,
ZERO_ADDRESS,
"0x",
{
value: fees[0], // need to fix this
}
)
)
.to.emit(hgt, "ReceiveFromChain")
.to.emit(hgtRemote, "SendToChain");
const hgtBalanceAfter = await ethers.provider.getBalance(hgt.address);
const adminBalanceAfter = await ethers.provider.getBalance(alice);
expect(BigNumber.from(hgtBalanceAfter)).to.eq(
BigNumber.from(hgtBalanceBefore).sub(parseEther("1"))
);
expect(BigNumber.from(adminBalanceAfter)).to.eq(
BigNumber.from(adminBalanceBefore).add(parseEther("1"))
);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment