Last active
June 5, 2023 10:42
-
-
Save sunnyRK/609aeee596c83424204e8f2b13ceebfc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}`, | |
}, | |
}, | |
], | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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