diff --git a/.gitmodules b/.gitmodules index 916ca16ca..ce1a6a0ef 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "lib/solady"] path = lib/solady url = https://github.com/Vectorized/solady +[submodule "lib/Permit2"] + path = lib/Permit2 + url = https://github.com/Uniswap/Permit2 diff --git a/audit/auditLog.json b/audit/auditLog.json index 3cecd5418..7e73b0108 100644 --- a/audit/auditLog.json +++ b/audit/auditLog.json @@ -34,19 +34,29 @@ "auditorGitHandle": "sujithsomraaj", "auditReportPath": "./audit/reports/2024.11.05_EmergencyPauseFacet_ReAudit.pdf", "auditCommitHash": "da61880ba3847c07c35b64a78b957ff845ec18ac" + }, + "audit20241122": { + "auditCompletedOn": "22.11.2024", + "auditedBy": "Sujith Somraaj (individual security researcher)", + "auditorGitHandle": "sujithsomraaj", + "auditReportPath": "./audit/reports/2024.11.22_Permit2Proxy.pdf", + "auditCommitHash": "0e3debb78abcdf9a9f934115338b611e16b039a0" } }, "auditedContracts": { - "EmergencyPauseFacet": { - "1.0.0": ["audit20240913"], - "1.0.1": ["audit20241105"] - }, "AcrossFacetV3": { "1.0.0": ["audit20241007"] }, "AcrossFacetPackedV3": { "1.0.0": ["audit20241007"] }, + "EmergencyPauseFacet": { + "1.0.0": ["audit20240913"], + "1.0.1": ["audit20241105"] + }, + "Permit2Proxy": { + "1.0.0": ["audit20241122"] + }, "ReceiverAcrossV3": { "1.0.0": ["audit20241007"] }, diff --git a/audit/reports/2024.11.22_Permit2Proxy.pdf b/audit/reports/2024.11.22_Permit2Proxy.pdf new file mode 100644 index 000000000..f23a830c8 Binary files /dev/null and b/audit/reports/2024.11.22_Permit2Proxy.pdf differ diff --git a/config/networks.json b/config/networks.json index ee9018e78..cbf583e05 100644 --- a/config/networks.json +++ b/config/networks.json @@ -102,9 +102,9 @@ "explorerUrl": "https://blastscan.io", "explorerApiUrl": "https://api.blastscan.io/api", "multicallAddress": "0xcA11bde05977b3631167028862bE2a173976CA11", - "safeApiUrl": "https://transaction.blast-safe.io/api", + "safeApiUrl": "https://safe-transaction-blast.safe.global/api", "safeAddress": "0xdf61270fDC1A892874Fd3C0143A0A4CBA74F4EF1", - "safeWebUrl": "https://blast-safe.io/transactions/queue?safe=blastmainnet:0xdf61270fDC1A892874Fd3C0143A0A4CBA74F4EF1", + "safeWebUrl": "https://app.safe.global/transactions/queue?safe=blast:0xdf61270fDC1A892874Fd3C0143A0A4CBA74F4EF1", "gasZipChainId": 96 }, "boba": { diff --git a/config/permit2Proxy.json b/config/permit2Proxy.json new file mode 100644 index 000000000..c4ac60ac2 --- /dev/null +++ b/config/permit2Proxy.json @@ -0,0 +1,31 @@ +{ + "mainnet": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "arbitrum": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "aurora": "", + "avalanche": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "base": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "blast": "0x000000000022d473030f116ddee9f6b43ac78ba3", + "boba": "", + "bsc": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "celo": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "fantom": "", + "fraxtal": "", + "fuse": "", + "gnosis": "", + "gravity": "", + "immutablezkevm": "", + "linea": "", + "mantle": "", + "metis": "", + "mode": "", + "moonbeam": "", + "moonriver": "", + "optimism": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "polygon": "0x000000000022D473030F116dDEE9F6B43aC78BA3", + "polygonzkevm": "", + "rootstock": "", + "scroll": "", + "sei": "", + "taiko": "", + "zksync": "0x0000000000225e31d15943971f47ad3022f714fa" +} \ No newline at end of file diff --git a/deployments/_deployments_log_file.json b/deployments/_deployments_log_file.json index cc38c5b17..28db164a6 100644 --- a/deployments/_deployments_log_file.json +++ b/deployments/_deployments_log_file.json @@ -24602,5 +24602,171 @@ ] } } + }, + "Permit2Proxy": { + "arbitrum": { + "staging": { + "1.0.0": [ + { + "ADDRESS": "0x6FC01BC9Ff6Cdab694Ec8Ca41B21a2F04C8c37E5", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-10-21 09:31:13", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000d3b2b0ac0afdd0d166a495f5e9fca4ecc715a782000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000009e606d0d2bba344b911e2f4eab95d9235a83fe15", + "SALT": "", + "VERIFIED": "true" + } + ] + }, + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 11:24:27", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000009e606d0d2bba344b911e2f4eab95d9235a83fe15", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "polygon": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 11:26:53", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000008bcc385948c73736423d38cc567cfede0f1826a3", + "SALT": "", + "VERIFIED": "true" + } + ] + }, + "staging": { + "1.0.0": [ + { + "ADDRESS": "0x6FC01BC9Ff6Cdab694Ec8Ca41B21a2F04C8c37E5", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-10-21 09:32:45", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000d3b2b0ac0afdd0d166a495f5e9fca4ecc715a782000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000008bcc385948c73736423d38cc567cfede0f1826a3", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "optimism": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 11:25:40", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000a8892ea3fddef2aa8afb1e3643a3284f978a5114", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "mainnet": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 11:10:40", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000037347dd595c49212c5fc2d95ea10d1085896f51e", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "avalanche": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 12:15:16", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000027d4eb2854d93a1a7df8e2aed1a535b080a6f6e4", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "base": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 12:26:53", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000001f6974c11b833eb52ea07e0b442510165d87d82e", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "blast": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 12:38:05", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000df61270fdc1a892874fd3c0143a0a4cba74f4ef1", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "bsc": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 12:39:31", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000020b6b31d76e054c3e4de6154feca385ca58c7c15", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "celo": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 13:03:21", + "CONSTRUCTOR_ARGS": "0x0000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000a89a87986e8ee1ac8fdacc5ac91627010ec9f772", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "zksync": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x6275f6631c955DC5dA9fBe8Dc7f24a3A5919443A", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-11-25 13:42:32", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000341e94069f53234fe6dabef707ad4248305257150000000000000000000000000000000000225e31d15943971f47ad3022f714fa00000000000000000000000002f1272aeacaf7bd8b30278bc2aa381cc623a744", + "SALT": "", + "VERIFIED": "true" + } + ] + } + } } -} \ No newline at end of file +} diff --git a/deployments/arbitrum.diamond.json b/deployments/arbitrum.diamond.json index f3dd714ee..b6c95d690 100644 --- a/deployments/arbitrum.diamond.json +++ b/deployments/arbitrum.diamond.json @@ -144,6 +144,10 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "GasZipFacet", + "Version": "1.0.0" } }, "Periphery": { @@ -152,6 +156,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", @@ -159,4 +164,4 @@ "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d" } } -} \ No newline at end of file +} diff --git a/deployments/arbitrum.json b/deployments/arbitrum.json index 85d203c12..be4f46d1d 100644 --- a/deployments/arbitrum.json +++ b/deployments/arbitrum.json @@ -48,8 +48,9 @@ "StargateFacetV2": "0x6e378C84e657C57b2a8d183CFf30ee5CC8989b61", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", "AcrossFacetV3": "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f" -} +} \ No newline at end of file diff --git a/deployments/arbitrum.staging.json b/deployments/arbitrum.staging.json index 69b369d95..b7df4ede9 100644 --- a/deployments/arbitrum.staging.json +++ b/deployments/arbitrum.staging.json @@ -46,6 +46,7 @@ "LiFuelFeeCollector": "0x94EA56D8049e93E0308B9c7d1418Baf6A7C68280", "TokenWrapper": "0xF63b27AE2Dc887b88f82E2Cc597d07fBB2E78E70", "EmergencyPauseFacet": "0x17Bb203F42d8e404ac7E8dB6ff972B7E8473850b", + "Permit2Proxy": "0x6FC01BC9Ff6Cdab694Ec8Ca41B21a2F04C8c37E5", "AcrossFacetV3": "0x6124C65B6264bE13f059b7C3A891a5b77DA8Bd95", "ReceiverAcrossV3": "0x3877f47B560819E96BBD7e7700a02dfACe36D696", "AcrossFacetPackedV3": "0x4352459F6BE1C7D1278F8c34Bb598b0feeB50f8b" diff --git a/deployments/aurora.diamond.json b/deployments/aurora.diamond.json index 16e7d04dc..b1843e7eb 100644 --- a/deployments/aurora.diamond.json +++ b/deployments/aurora.diamond.json @@ -60,18 +60,23 @@ "0x6e378C84e657C57b2a8d183CFf30ee5CC8989b61": { "Name": "StargateFacetV2", "Version": "1.0.1" + }, + "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { + "Name": "EmergencyPauseFacet", + "Version": "1.0.0" } }, "Periphery": { - "ERC20Proxy": "", - "Executor": "", + "ERC20Proxy": "0x5741A7FfE7c39Ca175546a54985fA79211290b51", + "Executor": "0x2dfaDAB8266483beD9Fd9A292Ce56596a2D1378D", "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", - "LiFiDEXAggregator": "", - "LiFuelFeeCollector": "", - "Receiver": "0x5439f8ca43f832DD21a28C5BF038dad4c07ad02c", + "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", + "LiFuelFeeCollector": "0x8E92e662573CBC66B0AB6A93B5FE291925508085", + "Permit2Proxy": "", + "Receiver": "", "ReceiverAcrossV3": "", - "ReceiverStargateV2": "", - "RelayerCelerIM": "", + "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", + "RelayerCelerIM": "0x6a8b11bF29C0546991DEcD6E0Db8cC7Fda22bA97", "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d" } } diff --git a/deployments/avalanche.diamond.json b/deployments/avalanche.diamond.json index 2a38d0dbe..44cc0e583 100644 --- a/deployments/avalanche.diamond.json +++ b/deployments/avalanche.diamond.json @@ -116,6 +116,10 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" } }, "Periphery": { @@ -124,6 +128,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/avalanche.json b/deployments/avalanche.json index c6378272c..07d97a104 100644 --- a/deployments/avalanche.json +++ b/deployments/avalanche.json @@ -45,5 +45,6 @@ "StargateFacetV2": "0x6e378C84e657C57b2a8d183CFf30ee5CC8989b61", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", - "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61" + "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" } \ No newline at end of file diff --git a/deployments/base.diamond.json b/deployments/base.diamond.json index 994fa4e55..1a4cfab47 100644 --- a/deployments/base.diamond.json +++ b/deployments/base.diamond.json @@ -132,6 +132,14 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" + }, + "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" } }, "Periphery": { @@ -140,6 +148,7 @@ "FeeCollector": "0x0A6d96E7f4D7b96CFE42185DF61E64d255c12DFf", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0xeC03B65CbDc5f8858b02F44EBa54C90664249fb1", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/base.json b/deployments/base.json index 8291f7601..e239176b5 100644 --- a/deployments/base.json +++ b/deployments/base.json @@ -41,5 +41,6 @@ "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", "AcrossFacetV3": "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", - "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f" -} + "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" +} \ No newline at end of file diff --git a/deployments/blast.diamond.json b/deployments/blast.diamond.json index 24daaddb6..872130e8c 100644 --- a/deployments/blast.diamond.json +++ b/deployments/blast.diamond.json @@ -73,7 +73,7 @@ "Name": "AcrossFacetPackedV3", "Version": "1.0.0" }, - "0x00990C0FfBB7eAB014351652aFB65AaE00db43A4": { + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { "Name": "", "Version": "" }, @@ -88,6 +88,7 @@ "FeeCollector": "0xF048e5816B0C7951AC179f656C5B86e5a79Bd7b5", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x0561fFe9855541C02D17951c93405A4407Df74BC", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "", diff --git a/deployments/blast.json b/deployments/blast.json index 519ddd42b..7ef518cf1 100644 --- a/deployments/blast.json +++ b/deployments/blast.json @@ -28,5 +28,6 @@ "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", "AcrossFacetV3": "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", - "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f" -} + "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" +} \ No newline at end of file diff --git a/deployments/boba.diamond.json b/deployments/boba.diamond.json index f9a009d95..6f989e752 100644 --- a/deployments/boba.diamond.json +++ b/deployments/boba.diamond.json @@ -72,6 +72,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x5439f8ca43f832DD21a28C5BF038dad4c07ad02c", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/bsc.diamond.json b/deployments/bsc.diamond.json index ebbff036e..8a9a182c4 100644 --- a/deployments/bsc.diamond.json +++ b/deployments/bsc.diamond.json @@ -120,6 +120,10 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" } }, "Periphery": { @@ -128,6 +132,7 @@ "FeeCollector": "0xbD6C7B0d2f68c2b7805d88388319cfB6EcB50eA9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/bsc.json b/deployments/bsc.json index b875005f3..87d20f70a 100644 --- a/deployments/bsc.json +++ b/deployments/bsc.json @@ -46,5 +46,6 @@ "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", "StargateFacetV2": "0x6e378C84e657C57b2a8d183CFf30ee5CC8989b61", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", - "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61" + "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" } \ No newline at end of file diff --git a/deployments/celo.diamond.json b/deployments/celo.diamond.json index 1a3abf9e4..8805dfad4 100644 --- a/deployments/celo.diamond.json +++ b/deployments/celo.diamond.json @@ -72,6 +72,7 @@ "FeeCollector": "0xF048e5816B0C7951AC179f656C5B86e5a79Bd7b5", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x0561fFe9855541C02D17951c93405A4407Df74BC", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/celo.json b/deployments/celo.json index d0980da36..baa221a3c 100644 --- a/deployments/celo.json +++ b/deployments/celo.json @@ -24,5 +24,6 @@ "AllBridgeFacet": "0x222b97E533220A47ad8700C396537D58e001808C", "GenericSwapFacetV3": "0xD8066332e52A210f7E6BD8F8D4F2be4197BE290D", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", - "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61" + "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" } \ No newline at end of file diff --git a/deployments/cronos.diamond.json b/deployments/cronos.diamond.json index ebc2b9096..f9657b085 100644 --- a/deployments/cronos.diamond.json +++ b/deployments/cronos.diamond.json @@ -2,12 +2,12 @@ "LiFiDiamond": { "Facets": { "0xf7993A8df974AD022647E63402d6315137c58ABf": { - "Name": "DiamondCutFacet", - "Version": "1.0.0" + "Name": "", + "Version": "" }, "0xF5ba8Db6fEA7aF820De35C8D0c294e17DBC1b9D2": { - "Name": "DiamondLoupeFacet", - "Version": "1.0.0" + "Name": "", + "Version": "" }, "0x6faA6906b9e4A59020e673910105567e809789E0": { "Name": "OwnershipFacet", @@ -62,10 +62,11 @@ "ERC20Proxy": "0x9B112948F3c71eBFb59961657b37c21328cFb01e", "Executor": "0xd00DaEC49Cd4F33Fe8542050294759cD971c7116", "FeeCollector": "0x11d40Dc8Ff0CE92F54A315aD8e674a55a866cBEe", - "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", - "LiFuelFeeCollector": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", - "ReceiverAcrossV3": "", + "LiFiDEXAggregator": "0xf88F6948C8AFf60c0B011f3175CDF459c66Ed035", + "LiFuelFeeCollector": "0x70D6cFE9146D6B6ebEb88BcB22fa220E78058D6F", + "Permit2Proxy": "", "Receiver": "0x4891e076b18FccEBE62962A26e74df85BB04168b", + "ReceiverAcrossV3": "", "ReceiverStargateV2": "", "RelayerCelerIM": "", "TokenWrapper": "0x693c18A628866BdD04956d9544Ce769C0e468149" diff --git a/deployments/fantom.diamond.json b/deployments/fantom.diamond.json index 0ea49d0a1..1fccb133a 100644 --- a/deployments/fantom.diamond.json +++ b/deployments/fantom.diamond.json @@ -88,6 +88,10 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" } }, "Periphery": { @@ -96,6 +100,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/fraxtal.diamond.json b/deployments/fraxtal.diamond.json index 519182896..52231e61b 100644 --- a/deployments/fraxtal.diamond.json +++ b/deployments/fraxtal.diamond.json @@ -68,6 +68,7 @@ "FeeCollector": "0x7956280Ec4B4d651C4083Ca737a1fa808b5319D8", "LiFiDEXAggregator": "0xE38621607316cB43367c134C65dca3f41B61250f", "LiFuelFeeCollector": "0x9870F0C91D722B3393383722968269496d919bD8", + "Permit2Proxy": "", "Receiver": "0xf22c55c50fF14d9AB1fa4D9DCA832085D143E854", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/fuse.diamond.json b/deployments/fuse.diamond.json index 269cce84f..2706f86b3 100644 --- a/deployments/fuse.diamond.json +++ b/deployments/fuse.diamond.json @@ -64,6 +64,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x5439f8ca43f832DD21a28C5BF038dad4c07ad02c", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/gnosis.diamond.json b/deployments/gnosis.diamond.json index 2b7b148a8..c0ba88aea 100644 --- a/deployments/gnosis.diamond.json +++ b/deployments/gnosis.diamond.json @@ -92,6 +92,10 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" } }, "Periphery": { @@ -100,6 +104,7 @@ "FeeCollector": "0xbD6C7B0d2f68c2b7805d88388319cfB6EcB50eA9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x5439f8ca43f832DD21a28C5BF038dad4c07ad02c", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/gravity.diamond.json b/deployments/gravity.diamond.json index ac7295607..f028bf2a5 100644 --- a/deployments/gravity.diamond.json +++ b/deployments/gravity.diamond.json @@ -56,6 +56,18 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" + }, + "0x49e93F6A99c590a8E70138D2710B9eDd88C077FF": { + "Name": "", + "Version": "" + }, + "0x325DA62543447A48c7b044C5642B87CeA88B0fd3": { + "Name": "", + "Version": "" } }, "Periphery": { @@ -64,6 +76,7 @@ "FeeCollector": "0x79540403cdE176Ca5f1fb95bE84A7ec91fFDEF76", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0x134f525AC05E4724e55C363A9C4FA35ceB13F88d", + "Permit2Proxy": "", "Receiver": "0x2DeB3bFa2b19024A0c1Ba299b6b79276f1F77b14", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0x6A3d6652fb7be72200a47313C092342218aAeb72", diff --git a/deployments/immutablezkevm.diamond.json b/deployments/immutablezkevm.diamond.json index afe36af97..7f786f1d3 100644 --- a/deployments/immutablezkevm.diamond.json +++ b/deployments/immutablezkevm.diamond.json @@ -64,6 +64,7 @@ "FeeCollector": "0x1a4E99aB56BBac95810C0A957F173054f6FA8fDc", "LiFiDEXAggregator": "0xAcD913Ad6936Bb662395ac9a66D75bFc77c165fF", "LiFuelFeeCollector": "0x677Fa29FFe6c8f03D6bbE789090Dceb498b7aaA4", + "Permit2Proxy": "", "Receiver": "0xCfDfbAa460EFAd6F58D4459d82863CfA137e4993", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/kaia.diamond.json b/deployments/kaia.diamond.json index c175272ce..0f1f0414c 100644 --- a/deployments/kaia.diamond.json +++ b/deployments/kaia.diamond.json @@ -72,6 +72,7 @@ "FeeCollector": "0x5e6525c873D6FD3D6BE0D9845018F6298583981d", "LiFiDEXAggregator": "0xE275759e85e5497A1B07EA65529187FD7E987509", "LiFuelFeeCollector": "0xD5F295EA94Bcd6792185542CFa5AB77DC4422B77", + "Permit2Proxy": "", "Receiver": "0x53F9ee918d173B19EA75DD5A304A6eDcfF52cc0c", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0xAF300C06AA7cff43640B7cE943a96142f6ABf0b1", diff --git a/deployments/linea.diamond.json b/deployments/linea.diamond.json index 1061ce51f..c807cf439 100644 --- a/deployments/linea.diamond.json +++ b/deployments/linea.diamond.json @@ -106,16 +106,24 @@ "Version": "1.0.1" }, "0x80b96CA9B47aCD6c2a888128fEb9b0F4Ea518FEc": { - "Name": "AcrossFacetV3", - "Version": "1.0.0" + "Name": "", + "Version": "" }, - "0xAfEB7e1DA0Ff4DcD0dbC4De3F51a933E2054B0ed": { + "0x922D1c381Cb5b0AFAAe9E7C86ed34FDE337766b0": { "Name": "AcrossFacetPackedV3", "Version": "1.0.0" }, "0xe07c030dDC7Fb9ca23b633b1028106DAA5fdbF96": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0x75943d7305310635945736D00235d825181018f3": { + "Name": "", + "Version": "" + }, + "0x2531368BAca8c5E85031FC0a9a2f148b65da389A": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" } }, "Periphery": { @@ -124,6 +132,7 @@ "FeeCollector": "0xA4A24BdD4608D7dFC496950850f9763B674F0DB2", "LiFiDEXAggregator": "", "LiFuelFeeCollector": "0x68B21d21509446Bf5449B6F5F8aBD4b3cfcbc3f8", + "Permit2Proxy": "", "Receiver": "0xdcBEcDE898c067cA58ABD01a7de51660bBD5A897", "ReceiverAcrossV3": "0x4BB377A1A624bDeF72d352891dc5E64087345fe6", "ReceiverStargateV2": "0x6CA57d9846f9a1fd48368762b743a047eC4f81A6", diff --git a/deployments/mainnet.diamond.json b/deployments/mainnet.diamond.json index 8428ec9f0..91eada7e8 100644 --- a/deployments/mainnet.diamond.json +++ b/deployments/mainnet.diamond.json @@ -168,6 +168,14 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" + }, + "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" } }, "Periphery": { @@ -176,6 +184,7 @@ "FeeCollector": "0xbD6C7B0d2f68c2b7805d88388319cfB6EcB50eA9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/mainnet.json b/deployments/mainnet.json index d28177b4c..9e2949597 100644 --- a/deployments/mainnet.json +++ b/deployments/mainnet.json @@ -59,5 +59,6 @@ "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", "AcrossFacetV3": "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", - "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f" -} + "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" +} \ No newline at end of file diff --git a/deployments/mantle.diamond.json b/deployments/mantle.diamond.json index ef7fe724e..c76fddcc6 100644 --- a/deployments/mantle.diamond.json +++ b/deployments/mantle.diamond.json @@ -64,6 +64,14 @@ "0x6e378C84e657C57b2a8d183CFf30ee5CC8989b61": { "Name": "StargateFacetV2", "Version": "1.0.1" + }, + "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { + "Name": "EmergencyPauseFacet", + "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "GasZipFacet", + "Version": "2.0.0" } }, "Periphery": { @@ -72,6 +80,7 @@ "FeeCollector": "0xF048e5816B0C7951AC179f656C5B86e5a79Bd7b5", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x2fA14922ABc117c4737260032C8fD6D9Ab35395A", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/metis.diamond.json b/deployments/metis.diamond.json index d47ff324a..fa6d3ab51 100644 --- a/deployments/metis.diamond.json +++ b/deployments/metis.diamond.json @@ -72,6 +72,10 @@ "0xD5734b44Bb7Ada52ea6503088612E70a2a612371": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xb518364B2F4e480eCc64998Da12F072A63a25093": { + "Name": "GasZipFacet", + "Version": "2.0.0" } }, "Periphery": { @@ -80,6 +84,7 @@ "FeeCollector": "0x27f0e36dE6B1BA8232f6c2e87E00A50731048C6B", "LiFiDEXAggregator": "0x9E4c63c9a0EDE2Ca2e772ee48C819Ca5CB4529AC", "LiFuelFeeCollector": "0x851450e3b624ea4b068c3E8cFBcf79cD03D31C54", + "Permit2Proxy": "", "Receiver": "0x0a4D7f27e8d24625eCb8d29d6445934a440A05E0", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0xe7392Fc0f61503dB53C70789c6F2c34C0675C929", diff --git a/deployments/mode.diamond.json b/deployments/mode.diamond.json index 3605b3b8e..0655024fa 100644 --- a/deployments/mode.diamond.json +++ b/deployments/mode.diamond.json @@ -73,7 +73,15 @@ "Name": "AcrossFacetPackedV3", "Version": "1.0.0" }, - "0x00990C0FfBB7eAB014351652aFB65AaE00db43A4": { + "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" + }, + "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { + "Name": "EmergencyPauseFacet", + "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { "Name": "", "Version": "" } @@ -84,6 +92,7 @@ "FeeCollector": "0xF048e5816B0C7951AC179f656C5B86e5a79Bd7b5", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x0561fFe9855541C02D17951c93405A4407Df74BC", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "", diff --git a/deployments/moonbeam.diamond.json b/deployments/moonbeam.diamond.json index 4f1306f10..afc910fcc 100644 --- a/deployments/moonbeam.diamond.json +++ b/deployments/moonbeam.diamond.json @@ -80,6 +80,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x5439f8ca43f832DD21a28C5BF038dad4c07ad02c", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/moonriver.diamond.json b/deployments/moonriver.diamond.json index e892b32a4..ddb14714b 100644 --- a/deployments/moonriver.diamond.json +++ b/deployments/moonriver.diamond.json @@ -84,6 +84,7 @@ "FeeCollector": "0xB0210dE78E28e2633Ca200609D9f528c13c26cD9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x5439f8ca43f832DD21a28C5BF038dad4c07ad02c", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/opbnb.diamond.json b/deployments/opbnb.diamond.json index 071d1bd29..a4635cd70 100644 --- a/deployments/opbnb.diamond.json +++ b/deployments/opbnb.diamond.json @@ -60,8 +60,9 @@ "FeeCollector": "0x6A2420650139854F17964b8C3Bb60248470aB57E", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xEc41F702d36b43a1E1d017Cb4da92F431dFA7a0E", - "ReceiverAcrossV3": "", + "Permit2Proxy": "", "Receiver": "0x423d018777dE97059129E046BBc1026548553A20", + "ReceiverAcrossV3": "", "ReceiverStargateV2": "", "RelayerCelerIM": "", "TokenWrapper": "0x077A38b812e57E2e76849954c880E1a2f5e0A68d" diff --git a/deployments/optimism.diamond.json b/deployments/optimism.diamond.json index 66cbfe053..b70f99ec2 100644 --- a/deployments/optimism.diamond.json +++ b/deployments/optimism.diamond.json @@ -144,6 +144,14 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" + }, + "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" } }, "Periphery": { @@ -152,6 +160,7 @@ "FeeCollector": "0xbD6C7B0d2f68c2b7805d88388319cfB6EcB50eA9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/optimism.json b/deployments/optimism.json index de6819514..1d43fc913 100644 --- a/deployments/optimism.json +++ b/deployments/optimism.json @@ -47,8 +47,9 @@ "StargateFacetV2": "0x6e378C84e657C57b2a8d183CFf30ee5CC8989b61", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", "AcrossFacetV3": "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f" -} +} \ No newline at end of file diff --git a/deployments/polygon.diamond.json b/deployments/polygon.diamond.json index bd7c4285e..bf5bb2900 100644 --- a/deployments/polygon.diamond.json +++ b/deployments/polygon.diamond.json @@ -144,6 +144,14 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" + }, + "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" } }, "Periphery": { @@ -152,6 +160,7 @@ "FeeCollector": "0xbD6C7B0d2f68c2b7805d88388319cfB6EcB50eA9", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9", "Receiver": "0x050e198E36A73a1e32F15C3afC58C4506d82f657", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/polygon.diamond.staging.json b/deployments/polygon.diamond.staging.json index fb1caab56..3114c1eb9 100644 --- a/deployments/polygon.diamond.staging.json +++ b/deployments/polygon.diamond.staging.json @@ -136,4 +136,4 @@ "TokenWrapper": "0xF63b27AE2Dc887b88f82E2Cc597d07fBB2E78E70" } } -} \ No newline at end of file +} diff --git a/deployments/polygon.json b/deployments/polygon.json index 0a8e98c7f..63741bcb8 100644 --- a/deployments/polygon.json +++ b/deployments/polygon.json @@ -54,5 +54,6 @@ "EmergencyPauseFacet": "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61", "AcrossFacetV3": "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", - "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f" -} + "AcrossFacetPackedV3": "0x20F3FFf5A89e988c4109A6e496a839480B1B558f", + "Permit2Proxy": "0x6307119078556Fc8aD77781DFC67df20d75FB4f9" +} \ No newline at end of file diff --git a/deployments/polygon.staging.json b/deployments/polygon.staging.json index 79d77d88d..de64abd96 100644 --- a/deployments/polygon.staging.json +++ b/deployments/polygon.staging.json @@ -46,5 +46,6 @@ "CelerCircleBridgeFacet": "0x371E073f6A09DCBEE1D2Ac56E940F878a0Ba9DAE", "HopFacetOptimized": "0xf82135385765f1324257ffF74489F16382EBBb8A", "SymbiosisFacet": "0x21571D628B0bCBeb954D5933A604eCac35bAF2c7", - "AcrossFacetV3": "0xe2e5428F972d9C0a5Ba433e0c402752b472dB248" + "AcrossFacetV3": "0xe2e5428F972d9C0a5Ba433e0c402752b472dB248", + "Permit2Proxy": "0x6FC01BC9Ff6Cdab694Ec8Ca41B21a2F04C8c37E5" } diff --git a/deployments/polygonzkevm.diamond.json b/deployments/polygonzkevm.diamond.json index 291e00f98..bc220885a 100644 --- a/deployments/polygonzkevm.diamond.json +++ b/deployments/polygonzkevm.diamond.json @@ -88,6 +88,7 @@ "FeeCollector": "0xB49EaD76FE09967D7CA0dbCeF3C3A06eb3Aa0cB4", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0xC850013FC01A264018D58D112000E32835D15fBC", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/rootstock.diamond.json b/deployments/rootstock.diamond.json index aaabd6558..c48e8aba9 100644 --- a/deployments/rootstock.diamond.json +++ b/deployments/rootstock.diamond.json @@ -64,6 +64,7 @@ "FeeCollector": "0xF048e5816B0C7951AC179f656C5B86e5a79Bd7b5", "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x0561fFe9855541C02D17951c93405A4407Df74BC", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/scroll.diamond.json b/deployments/scroll.diamond.json index 4a9f50126..6a4b71f5e 100644 --- a/deployments/scroll.diamond.json +++ b/deployments/scroll.diamond.json @@ -92,14 +92,23 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" + }, + "0x6e00e0a7685Ca22c288d56D9E7924746B5043Ee7": { + "Name": "AcrossFacetV3", + "Version": "1.0.0" } }, "Periphery": { "ERC20Proxy": "0xA950Ac46b0b844c0564d18A54A9685e614B9086C", "Executor": "0x7078d1DE45C7D3e87f71D5DA663db2a8Ee1dfEbe", "FeeCollector": "0xF048e5816B0C7951AC179f656C5B86e5a79Bd7b5", - "LiFiDEXAggregator": "0x6140b987d6B51Fd75b66C3B07733Beb5167c42fc", + "LiFiDEXAggregator": "0x78bF01555bCF05e6B1d4dad017dBD0A105652DC9", "LiFuelFeeCollector": "0xc02FFcdD914DbA646704439c6090BAbaD521d04C", + "Permit2Proxy": "", "Receiver": "0x0561fFe9855541C02D17951c93405A4407Df74BC", "ReceiverAcrossV3": "0xB9CEc304899037E661F49DdFa7f64943b5920072", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/sei.diamond.json b/deployments/sei.diamond.json index 835c2e91d..a3b88f717 100644 --- a/deployments/sei.diamond.json +++ b/deployments/sei.diamond.json @@ -68,6 +68,7 @@ "FeeCollector": "0x7956280Ec4B4d651C4083Ca737a1fa808b5319D8", "LiFiDEXAggregator": "0xfdE9CE4e17B650efdcA13d524F132876700d806f", "LiFuelFeeCollector": "0x9870F0C91D722B3393383722968269496d919bD8", + "Permit2Proxy": "", "Receiver": "0xf22c55c50fF14d9AB1fa4D9DCA832085D143E854", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0x1493e7B8d4DfADe0a178dAD9335470337A3a219A", diff --git a/deployments/taiko.diamond.json b/deployments/taiko.diamond.json index c8ff2a516..8e928bc2f 100644 --- a/deployments/taiko.diamond.json +++ b/deployments/taiko.diamond.json @@ -68,6 +68,7 @@ "FeeCollector": "0xDd8A081efC90DFFD79940948a1528C51793C4B03", "LiFiDEXAggregator": "0xcaA342e4f781d63EF41E220D7622B97E66BAEcF3", "LiFuelFeeCollector": "0xff2F39692A90262b8Ed4DFD92799bB450425773F", + "Permit2Proxy": "", "Receiver": "0xe38326Ae727e3fA6669249063Ce7b8ea1754e756", "ReceiverAcrossV3": "", "ReceiverStargateV2": "0x6CA57d9846f9a1fd48368762b743a047eC4f81A6", diff --git a/deployments/worldchain.diamond.json b/deployments/worldchain.diamond.json index 6eaea8776..e5d2cdd2b 100644 --- a/deployments/worldchain.diamond.json +++ b/deployments/worldchain.diamond.json @@ -1,76 +1,79 @@ { - "LiFiDiamond": { - "Facets": { - "0x57FdfF2e36De6c8a8Cde297B150Ae291132Eae8d": { - "Name": "DiamondCutFacet", - "Version": "1.0.0" - }, - "0xA1a4d577709dC4A70CA38F1D41562fab3aD09D3f": { - "Name": "DiamondLoupeFacet", - "Version": "1.0.0" - }, - "0x81Ae738700D8f1e5BB2A200584174cDf17Fb5455": { - "Name": "OwnershipFacet", - "Version": "1.0.0" - }, - "0xfA009cd56d35AE3BbdF975135b0BAE9b403c7da1": { - "Name": "WithdrawFacet", - "Version": "1.0.0" - }, - "0xE154389c1bAE241F220661131b7AfDc1514C55c7": { - "Name": "DexManagerFacet", - "Version": "1.0.0" - }, - "0x314E1E760316050B0D6338bCf3d689b8D301F593": { - "Name": "AccessManagerFacet", - "Version": "1.0.0" - }, - "0x54ECfbAaeb49c864a9c45C70B785ca6C70c66453": { - "Name": "PeripheryRegistryFacet", - "Version": "1.0.0" - }, - "0x14Dd70456Bfe4Cd8b605f7A0d24b3A74aCe99713": { - "Name": "LIFuelFacet", - "Version": "1.0.0" - }, - "0xd2B3b3605e630232c13111458Ae3a97d13c8F477": { - "Name": "GenericSwapFacet", - "Version": "1.0.0" - }, - "0xBa713B18c806EcdEEE49FAec623dE2D872192872": { - "Name": "GenericSwapFacetV3", - "Version": "1.0.0" - }, - "0xe6C6A35684308f2DaadbeeA50B62CFEaAFaa407E": { - "Name": "StandardizedCallFacet", - "Version": "1.0.0" - }, - "0x1feB868BF64AdC552E051fB7387681F78b988a81": { - "Name": "CalldataVerificationFacet", - "Version": "1.0.0" - }, - "0xF6Eff8df65Fc4a4c1528761Aa727b5471956A844": { - "Name": "EmergencyPauseFacet", - "Version": "1.0.0" - }, - "0xB5dD83183fD7CCF859b227CA83663a034d5B2f92": { - "Name": "AcrossFacetV3", - "Version": "1.0.0" - }, - "0x90ADbFc03002aaA3d9FEdf2517D593CfD93e6c57": { - "Name": "AcrossFacetPackedV3", - "Version": "1.0.0" - } - }, - "Periphery": { - "ERC20Proxy": "0x98750e70Cf1313D9702f0f57D399DD0bA05d16E0", - "Executor": "0xd9318fFE1EbbfA71049A443e623Be566067C9D6B", - "FeeCollector": "0x50D5a8aCFAe13Dceb217E9a071F6c6Bd5bDB4155", - "Receiver": "0xD9e3837E42198aaFc13cb51536d7c31f590aD6Fd", - "LiFuelFeeCollector": "0x8f023b4193a6b18C227B4a755f8e28B3D30Ef9a1", - "TokenWrapper": "0x603a538477d44064eA5A5d8C345b4Ff6fca1142a", - "LiFiDEXAggregator": "0x2321F1a63A683a1F3634Dbe1CbA0d657D5F56d54", - "ReceiverAcrossV3": "0xD263a23453CB9A77860ed6393A2B9a55AF70EFAb" - } + "LiFiDiamond": { + "Facets": { + "0x57FdfF2e36De6c8a8Cde297B150Ae291132Eae8d": { + "Name": "DiamondCutFacet", + "Version": "" + }, + "0xA1a4d577709dC4A70CA38F1D41562fab3aD09D3f": { + "Name": "DiamondLoupeFacet", + "Version": "" + }, + "0x81Ae738700D8f1e5BB2A200584174cDf17Fb5455": { + "Name": "OwnershipFacet", + "Version": "" + }, + "0xfA009cd56d35AE3BbdF975135b0BAE9b403c7da1": { + "Name": "WithdrawFacet", + "Version": "" + }, + "0xE154389c1bAE241F220661131b7AfDc1514C55c7": { + "Name": "DexManagerFacet", + "Version": "" + }, + "0x314E1E760316050B0D6338bCf3d689b8D301F593": { + "Name": "AccessManagerFacet", + "Version": "" + }, + "0x54ECfbAaeb49c864a9c45C70B785ca6C70c66453": { + "Name": "PeripheryRegistryFacet", + "Version": "" + }, + "0x14Dd70456Bfe4Cd8b605f7A0d24b3A74aCe99713": { + "Name": "LIFuelFacet", + "Version": "" + }, + "0xd2B3b3605e630232c13111458Ae3a97d13c8F477": { + "Name": "GenericSwapFacet", + "Version": "" + }, + "0xBa713B18c806EcdEEE49FAec623dE2D872192872": { + "Name": "GenericSwapFacetV3", + "Version": "1.0.1" + }, + "0xe6C6A35684308f2DaadbeeA50B62CFEaAFaa407E": { + "Name": "StandardizedCallFacet", + "Version": "" + }, + "0x1feB868BF64AdC552E051fB7387681F78b988a81": { + "Name": "CalldataVerificationFacet", + "Version": "" + }, + "0xF6Eff8df65Fc4a4c1528761Aa727b5471956A844": { + "Name": "EmergencyPauseFacet", + "Version": "" + }, + "0xB5dD83183fD7CCF859b227CA83663a034d5B2f92": { + "Name": "AcrossFacetV3", + "Version": "" + }, + "0x90ADbFc03002aaA3d9FEdf2517D593CfD93e6c57": { + "Name": "AcrossFacetPackedV3", + "Version": "" + } + }, + "Periphery": { + "ERC20Proxy": "0x98750e70Cf1313D9702f0f57D399DD0bA05d16E0", + "Executor": "0xd9318fFE1EbbfA71049A443e623Be566067C9D6B", + "FeeCollector": "0x50D5a8aCFAe13Dceb217E9a071F6c6Bd5bDB4155", + "LiFiDEXAggregator": "0x2321F1a63A683a1F3634Dbe1CbA0d657D5F56d54", + "LiFuelFeeCollector": "0x8f023b4193a6b18C227B4a755f8e28B3D30Ef9a1", + "Permit2Proxy": "", + "Receiver": "0xD9e3837E42198aaFc13cb51536d7c31f590aD6Fd", + "ReceiverAcrossV3": "0xD263a23453CB9A77860ed6393A2B9a55AF70EFAb", + "ReceiverStargateV2": "", + "RelayerCelerIM": "", + "TokenWrapper": "0x603a538477d44064eA5A5d8C345b4Ff6fca1142a" } + } } \ No newline at end of file diff --git a/deployments/xlayer.diamond.json b/deployments/xlayer.diamond.json index dd7c1a9ce..7fbb18f54 100644 --- a/deployments/xlayer.diamond.json +++ b/deployments/xlayer.diamond.json @@ -60,6 +60,10 @@ "0x6F2baA7cd5F156CA1B132F7FF11E0fa2aD775F61": { "Name": "EmergencyPauseFacet", "Version": "1.0.0" + }, + "0xF5c923a087fb3c554579e2DD10AB6E37E0f6F849": { + "Name": "", + "Version": "" } }, "Periphery": { @@ -68,6 +72,7 @@ "FeeCollector": "0xC69994fd72824ca98F8a0B1E2ABc954E65a91cf4", "LiFiDEXAggregator": "0x2321F1a63A683a1F3634Dbe1CbA0d657D5F56d54", "LiFuelFeeCollector": "0x12904D12A84702f9F079E1e393fdAbD313496e97", + "Permit2Proxy": "", "Receiver": "0xE33aFf67082eD48A162996670A3FC80AD01C4B5D", "ReceiverAcrossV3": "", "ReceiverStargateV2": "", diff --git a/deployments/zksync.diamond.json b/deployments/zksync.diamond.json index 94de61cf1..24ad7db90 100644 --- a/deployments/zksync.diamond.json +++ b/deployments/zksync.diamond.json @@ -10,7 +10,7 @@ "Version": "1.0.0" }, "0xCe81D9bB9D9605FFF296CCF8Af6b6B38f02Cf15d": { - "Name": "", + "Name": "CBridgeFacetPacked", "Version": "" }, "0x862FB4813657A40D1828Cac1e28a600625D78fC0": { @@ -69,7 +69,11 @@ "Name": "AcrossFacetPackedV3", "Version": "1.0.0" }, - "0x57C72BFf1514cd5b66FE84Ac462412B15e286Fa8": { + "0xcF8c70683D7c0E2a094348896A46407646b94859": { + "Name": "EmergencyPauseFacet", + "Version": "1.0.0" + }, + "0x313c27Aad40c7e0A0b923b539F05617D8114566D": { "Name": "", "Version": "" } @@ -80,6 +84,7 @@ "FeeCollector": "0x8dBf6f59187b2EB36B980F3D8F4cFC6DC4E4642e", "LiFiDEXAggregator": "0x1F683faf1E2a770aa75f7B2e92117A5c11183E9C", "LiFuelFeeCollector": "0xB87C536E048Cfc082187E559fCFeFc3f1c89aEc7", + "Permit2Proxy": "0x6275f6631c955DC5dA9fBe8Dc7f24a3A5919443A", "Receiver": "0xdeDB2DAe4a9BC63910a722a3b7DC930C7E6f6421", "ReceiverAcrossV3": "0xFa94c1A99799B3cA89DE6cbB3ccCDEcf1da62aFE", "ReceiverStargateV2": "", diff --git a/deployments/zksync.json b/deployments/zksync.json index 01317c553..5642cdaba 100644 --- a/deployments/zksync.json +++ b/deployments/zksync.json @@ -22,5 +22,6 @@ "LiFiDEXAggregator": "0x1F683faf1E2a770aa75f7B2e92117A5c11183E9C", "AcrossFacetV3": "0x2e47355B70D6935C6A69d5F67e0aFe437791138e", "ReceiverAcrossV3": "0xFa94c1A99799B3cA89DE6cbB3ccCDEcf1da62aFE", - "AcrossFacetPackedV3": "0x9243578F60a2A3821642481b5851578cE92d9a78" -} + "AcrossFacetPackedV3": "0x9243578F60a2A3821642481b5851578cE92d9a78", + "Permit2Proxy": "0x6275f6631c955DC5dA9fBe8Dc7f24a3A5919443A" +} \ No newline at end of file diff --git a/docs/Permit2Proxy.md b/docs/Permit2Proxy.md new file mode 100644 index 000000000..fa248bf27 --- /dev/null +++ b/docs/Permit2Proxy.md @@ -0,0 +1,126 @@ +# Permit2 Proxy + +## Description + +Periphery contract which enables gasless and semi-gasless transaction flows +enabled through ERC20 Permit and Uniswap's Permit2 + +## How To Use + +The contract has a number of methods for making gasless and semi-gasless calls +as well as a few helpful utility methods. + +The following methods are available: + +This method is used to execute a transaction where the approval is granted +using an ERC20 Permit signature. It can only be called by the signer in order +to prevent front-running attacks. + +```solidity +/// @notice Allows to bridge tokens through a LI.FI diamond contract using +/// an EIP2612 gasless permit (only works with tokenAddresses that +/// implement EIP2612) (in contrast to Permit2, calldata and diamondAddress +/// are not signed by the user and could therefore be replaced by the user) +/// Can only be called by the permit signer to prevent front-running. +/// @param tokenAddress Address of the token to be bridged +/// @param amount Amount of tokens to be bridged +/// @param deadline Transaction must be completed before this timestamp +/// @param v User signature (recovery ID) +/// @param r User signature (ECDSA output) +/// @param s User signature (ECDSA output) +/// @param diamondCalldata Address of the token to be bridged +function callDiamondWithEIP2612Signature( + address tokenAddress, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s, + bytes calldata diamondCalldata +) public payable +```` + +This method is used to execute a transaction where the approval is granted via +Uniswap's Permit2 contract. It can only be called by the signer in order to +prevent front-running attacks. + +```solidity +/// @notice Allows to bridge tokens of one type through a LI.FI diamond +/// contract using Uniswap's Permit2 contract and a user signature +/// that verifies allowance. The calldata can be changed by the +/// user. Can only be called by the permit signer to prevent +/// front-running. +/// @param _diamondCalldata the calldata to execute +/// @param _permit the Uniswap Permit2 parameters +/// @param _signature the signature giving approval to transfer tokens +function callDiamondWithPermit2( + bytes calldata _diamondCalldata, + ISignatureTransfer.PermitTransferFrom calldata _permit, + bytes calldata _signature +) external payable +``` + +This method enables a gasless flow by allowing a user to sign a Uniswap Permit2 +message hash which includes a "witness" type. This extra type restricts which +calldata can be called during execution and cannot be changed. Anyone with the +signature can execute the transaction on behalf of the signer. + +```solidity +/// @notice Allows to bridge tokens of one type through a LI.FI diamond +/// contract using Uniswap's Permit2 contract and a user signature +/// that verifies allowance, diamondAddress and diamondCalldata +/// @param _diamondCalldata the calldata to execute +/// @param _signer the signer giving permission to transfer tokens +/// @param _permit the Uniswap Permit2 parameters +/// @param _signature the signature giving approval to transfer tokens +function callDiamondWithPermit2Witness( + bytes calldata _diamondCalldata, + address _signer, + ISignatureTransfer.PermitTransferFrom calldata _permit, + bytes calldata _signature +) external payable +``` + +There are a few utility methods to make it easier to generate the necessary +signature for the gasless flow. + +Calling this method will return a valid message hash that can then be signed +in order to be executed later by another wallet. + +```solidity +/// @notice utitlity method for constructing a valid Permit2 message hash +/// @param _diamondCalldata the calldata to execute +/// @param _assetId the address of the token to approve +/// @param _amount amount of tokens to approve +/// @param _nonce the nonce to use +/// @param _deadline the expiration deadline +function getPermit2MsgHash( + bytes calldata _diamondCalldata, + address _assetId, + uint256 _amount, + uint256 _nonce, + uint256 _deadline +) external view returns (bytes32 msgHash) +``` + +Permit2 nonces are non-sequential and are a bit complicated to work with. The +following utility methods allow you to fetch the next valid nonce or sequence +of nonces for use when generating Permit2 signatures. + +```solidity +/// @notice Finds the next valid nonce for a user, starting from 0. +/// @param owner The owner of the nonces +/// @return nonce The first valid nonce starting from 0 +function nextNonce(address owner) external view returns (uint256 nonce) + +/// @notice Finds the next valid nonce for a user, after from a given nonce. +/// @dev This can be helpful if you're signing multiple nonces in a row and +/// need the next nonce to sign but the start one is still valid. +/// @param owner The owner of the nonces +/// @param start The nonce to start from +/// @return nonce The first valid nonce after the given nonce +function nextNonceAfter( + address owner, + uint256 start +) external view returns (uint256 nonce) +``` diff --git a/docs/README.md b/docs/README.md index e13a483ff..b64bbc7e9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -61,3 +61,4 @@ - [Receiver](./Receiver.md) - [ReceiverStargateV2](./ReceiverStargateV2.md) - [RelayerCelerIM](./RelayerCelerIM.md) +- [Permit2Proxy](./Permit2Proxy.md) diff --git a/lib/Permit2 b/lib/Permit2 new file mode 160000 index 000000000..cc56ad0f3 --- /dev/null +++ b/lib/Permit2 @@ -0,0 +1 @@ +Subproject commit cc56ad0f3439c502c246fc5cfcc3db92bb8b7219 diff --git a/package.json b/package.json index 6b18b3b72..1be232436 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "@safe-global/safe-apps-sdk": "^9.0.0", "@safe-global/safe-core-sdk-types": "^4.1.0", "@uma/sdk": "^0.22.1", + "@uniswap/permit2-sdk": "^1.3.0", "@uniswap/sdk": "^3.0.3", "chalk": "4.1.2", "citty": "^0.1.6", diff --git a/remappings.txt b/remappings.txt index cf75a7770..d4a7a4506 100644 --- a/remappings.txt +++ b/remappings.txt @@ -9,7 +9,7 @@ celer-network/=lib/sgn-v2-contracts/ create3-factory/=lib/create3-factory/src/ solmate/=lib/solmate/src/ solady/=lib/solady/src/ - +permit2/=lib/Permit2/src/ ds-test/=lib/ds-test/src/ forge-std/=lib/forge-std/src/ diff --git a/script/demoScripts/demoPermit2.ts b/script/demoScripts/demoPermit2.ts new file mode 100644 index 000000000..e12c71d58 --- /dev/null +++ b/script/demoScripts/demoPermit2.ts @@ -0,0 +1,158 @@ +import { + http, + createPublicClient, + parseAbi, + Hex, + parseUnits, + createWalletClient, + PublicClient, +} from 'viem' +import { privateKeyToAccount, sign } from 'viem/accounts' +import { arbitrum } from 'viem/chains' +import { defineCommand, runMain } from 'citty' +import { PermitTransferFrom, SignatureTransfer } from '@uniswap/Permit2-sdk' + +// Sample Transfer: +// sent: +// https://arbiscan.io/tx/0x8d0caf2b4fda6688b5ab36254632f6b6412cf25f0f262689ed41a2a21fe489f1 +// status: +// https://scan.li.fi/tx/0x8d0caf2b4fda6688b5ab36254632f6b6412cf25f0f262689ed41a2a21fe489f1 +// received: +// https://polygonscan.com/tx/0x5dda19403942912027ef5e941e844de3a2a65b0c5a4173e3d388a71a54e5e635 + +const USDT_ADDRESS = '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' +const PERMIT2_PROXY_ADDRESS = '0xA3C7a31a2A97b847D967e0B755921D084C46a742' +const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3' + +/** + * Get the nonce from the PERMIT2 contract + */ +const getNonceForAddress = async ( + client: PublicClient, + address: `0x${string}` +): Promise => { + const permit2ProxyAbi = parseAbi([ + 'function nextNonce(address owner) external view returns (uint256)', + ]) + + return client.readContract({ + address: PERMIT2_PROXY_ADDRESS, + abi: permit2ProxyAbi, + functionName: 'nextNonce', + args: [address], + }) +} + +/** + * Generate permit data + */ +const getPermitData = async (params: { + userAddress: `0x${string}` + tokenAddress: `0x${string}` + amount: bigint + deadline: bigint +}) => { + const client = createPublicClient({ + chain: arbitrum, + transport: http(), + }) + + // Get latest block + const block = await client.getBlock() + const _deadline = block.timestamp + params.deadline + const nonce = await getNonceForAddress(client, params.userAddress) + + // build hash + const permitTransferFrom: PermitTransferFrom = { + permitted: { + token: params.tokenAddress, + amount: params.amount, + }, + nonce, + spender: PERMIT2_PROXY_ADDRESS, + deadline: _deadline, + } + const msgHash: `0x${string}` = SignatureTransfer.hash( + permitTransferFrom, + PERMIT2_ADDRESS, + arbitrum.id + ) as `0x${string}` + + const transferFromData: [[`0x${string}`, bigint], bigint, bigint] = [ + [params.tokenAddress, params.amount], + nonce, + _deadline, + ] + + return { + msgHash, + transferFromData, + } +} + +const main = defineCommand({ + meta: { + name: 'demo-permit2', + description: 'Demonstrate a Permit2 tx', + }, + args: { + signerKey: { + type: 'string', + description: 'Private key of signer', + required: true, + }, + }, + async run({ args }) { + const SIGNER_PRIVATE_KEY = `0x${args.signerKey}` as Hex + + // Setup the required ABI + const permit2ProxyAbi = parseAbi([ + 'function callDiamondWithPermit2(bytes,((address,uint256),uint256,uint256),bytes) external', + 'function nextNonce(address owner) external view returns (uint256)', + ]) + + // Setup a signer account + const account = privateKeyToAccount(SIGNER_PRIVATE_KEY) + + // Get calldata to bridge USDT from LIFI API + const url = + 'https://li.quest/v1/quote?fromChain=ARB&toChain=POL&fromToken=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9&toToken=0xc2132D05D31c914a87C6611C10748AEb04B58e8F&fromAddress=0xb9c0dE368BECE5e76B52545a8E377a4C118f597B&toAddress=0xb9c0dE368BECE5e76B52545a8E377a4C118f597B&fromAmount=5000000' + const options = { method: 'GET', headers: { accept: 'application/json' } } + const lifiResp = await fetch(url, options) + const calldata = (await lifiResp.json()).transactionRequest.data + + // Get Hash + const permitData = await getPermitData({ + userAddress: account.address, + tokenAddress: USDT_ADDRESS, + amount: parseUnits('5', 6), + deadline: 1200n, // 20min + }) + console.log(permitData) + + // Sign the message hash + const signature = await sign({ + hash: permitData.msgHash, + privateKey: SIGNER_PRIVATE_KEY, + to: 'hex', + }) + console.log('signature', signature) + + // Instantiate the executor account and a WRITE enabled client + const executorAccount = privateKeyToAccount(SIGNER_PRIVATE_KEY) + const walletClient = createWalletClient({ + account: executorAccount, + chain: arbitrum, + transport: http(), + }) + const tx = await walletClient.writeContract({ + address: PERMIT2_PROXY_ADDRESS, + abi: permit2ProxyAbi, + functionName: 'callDiamondWithPermit2', + args: [calldata, permitData.transferFromData, signature], + }) + console.log(`Transfers submitted in tx: ${tx}`) + }, +}) + +runMain(main) diff --git a/script/demoScripts/demoPermit2Proxy.ts b/script/demoScripts/demoPermit2Proxy.ts new file mode 100644 index 000000000..af37ab52d --- /dev/null +++ b/script/demoScripts/demoPermit2Proxy.ts @@ -0,0 +1,117 @@ +import { + http, + createPublicClient, + parseAbi, + Hex, + parseUnits, + serializeSignature, + createWalletClient, +} from 'viem' +import { privateKeyToAccount, sign } from 'viem/accounts' +import { arbitrum } from 'viem/chains' +import { defineCommand, runMain } from 'citty' + +const DIAMOND_ADDRESS = '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE' +const USDT_ADDRESS = '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' +const PERMIT2_PROXY_ADDRESS = '0xA3C7a31a2A97b847D967e0B755921D084C46a742' +const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3' +const PRIVATE_KEY = `0x${process.env.PRIVATE_KEY}` + +const main = defineCommand({ + meta: { + name: 'demo-permit2', + description: 'Demonstrate a Permit2 tx', + }, + args: { + signerKey: { + type: 'string', + description: 'Private key of signer', + required: true, + }, + executorKey: { + type: 'string', + description: 'Private key of the executor', + required: true, + }, + }, + async run({ args }) { + const SIGNER_PRIVATE_KEY = `0x${args.signerKey}` as Hex + const EXECUTOR_PRIVATE_KEY = `0x${args.executorKey}` as Hex + + // Setup the required ABI + const permit2ProxyAbi = parseAbi([ + 'function getPermit2MsgHash(bytes,address,uint256,uint256,uint256) external view returns (bytes32)', + 'function nextNonce(address owner) external view returns (uint256)', + 'function callDiamondWithPermit2Witness(bytes,address,((address,uint256),uint256,uint256),bytes) external', + ]) + + // Setup a READ-ONLY client + const client = createPublicClient({ + chain: arbitrum, + transport: http(), + }) + + // Setup a signer account + const account = privateKeyToAccount(SIGNER_PRIVATE_KEY) + + // Get calldata to bridge USDT from LIFI API + const url = + 'https://li.quest/v1/quote?fromChain=ARB&toChain=POL&fromToken=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9&toToken=0xc2132D05D31c914a87C6611C10748AEb04B58e8F&fromAddress=0xb9c0dE368BECE5e76B52545a8E377a4C118f597B&toAddress=0xb9c0dE368BECE5e76B52545a8E377a4C118f597B&fromAmount=5000000' + const options = { method: 'GET', headers: { accept: 'application/json' } } + const lifiResp = await fetch(url, options) + const calldata = (await lifiResp.json()).transactionRequest.data + + // Get the nonce from the PERMIT2 contract + const nonce = await client.readContract({ + address: PERMIT2_PROXY_ADDRESS, + abi: permit2ProxyAbi, + functionName: 'nextNonce', + args: [account.address], + }) + + // Get latest block + const block = await client.getBlock() + + // Construct a valid message hash to sign using Permit2Proxy's utility func + const msgHash = await client.readContract({ + address: PERMIT2_PROXY_ADDRESS, + abi: permit2ProxyAbi, + functionName: 'getPermit2MsgHash', + args: [ + calldata, + USDT_ADDRESS, + parseUnits('5', 6), + nonce, + block.timestamp + 1200n, // 20 min deadline + ], + }) + console.log(msgHash) + + // Sign the message hash + const rsvSig = await sign({ hash: msgHash, privateKey: SIGNER_PRIVATE_KEY }) + const signature = serializeSignature(rsvSig) + console.log(signature) + + // Setup the parameters for the executor to call + const tokenPermissions = [USDT_ADDRESS, parseUnits('5', 6)] + const permit = [tokenPermissions, nonce, block.timestamp + 1200n] + + // Instantiate the executor account and a WRITE enabled client + const executorAccount = privateKeyToAccount(EXECUTOR_PRIVATE_KEY) + const walletClient = createWalletClient({ + account: executorAccount, + chain: arbitrum, + transport: http(), + }) + + // Execute using the Permit2 Proxy + const tx = await walletClient.writeContract({ + address: PERMIT2_PROXY_ADDRESS, + abi: permit2ProxyAbi, + functionName: 'callDiamondWithPermit2Witness', + args: [calldata, account.address, permit, signature], + }) + }, +}) + +runMain(main) diff --git a/script/deploy/_targetState.json b/script/deploy/_targetState.json index 6c406e982..189be8d69 100644 --- a/script/deploy/_targetState.json +++ b/script/deploy/_targetState.json @@ -12,9 +12,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -42,11 +42,11 @@ "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", "HopFacetOptimized": "2.0.0", - "HyphenFacet": "1.0.0", "MayanFacet": "1.0.0", "OmniBridgeFacet": "1.0.0", "OptimismBridgeFacet": "1.0.0", "PolygonBridgeFacet": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -69,9 +69,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -97,8 +97,8 @@ "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", "HopFacetOptimized": "2.0.0", - "HyphenFacet": "1.0.0", "MayanFacet": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -120,9 +120,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -139,8 +139,9 @@ "CBridgeFacetPacked": "1.0.3", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0", - "HyphenFacet": "1.0.0", "MayanFacet": "1.0.0", + "OpBNBBridgeFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract OpBNBBridgeFacet\u001b[0m\u001b[0m", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -163,9 +164,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -174,7 +175,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AmarokFacet": "3.0.0", "AmarokFacetPacked": "1.0.0", "CBridgeFacet": "1.0.0", @@ -198,9 +198,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -209,11 +209,9 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0", - "HyphenFacet": "1.0.0", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0" } @@ -233,9 +231,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -251,8 +249,8 @@ "CelerCircleBridgeFacet": "1.0.1", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0", - "HyphenFacet": "1.0.0", "MayanFacet": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -275,9 +273,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -303,8 +301,8 @@ "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", "HopFacetOptimized": "2.0.0", - "HyphenFacet": "1.0.0", "MayanFacet": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -326,9 +324,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -354,7 +352,7 @@ "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", "HopFacetOptimized": "2.0.0", - "HyphenFacet": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", "ReceiverStargateV2": "1.0.0", @@ -375,9 +373,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -386,7 +384,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0" @@ -406,9 +403,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -417,7 +414,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "SquidFacet": "1.0.0" } @@ -436,9 +432,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -446,8 +442,7 @@ "Receiver": "2.0.2", "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0" + "LiFiDEXAggregator": "1.0.0" } } }, @@ -467,9 +462,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -478,7 +473,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0", @@ -500,9 +494,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -511,43 +505,12 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "SymbiosisFacet": "1.0.0" } } }, - "arbitrumnova": { - "production": { - "LiFiDiamond": { - "DiamondCutFacet": "1.0.0", - "DiamondLoupeFacet": "1.0.0", - "OwnershipFacet": "1.0.0", - "DexManagerFacet": "1.0.1", - "AccessManagerFacet": "1.0.0", - "WithdrawFacet": "1.0.0", - "PeripheryRegistryFacet": "1.0.0", - "GenericSwapFacet": "1.0.0", - "GenericSwapFacetV3": "1.0.1", - "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", - "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", - "LiFiDiamond": "1.0.0", - "ERC20Proxy": "1.0.0", - "Executor": "2.0.0", - "FeeCollector": "1.0.0", - "Receiver": "2.0.2", - "LiFuelFeeCollector": "1.0.1", - "TokenWrapper": "1.0.0", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", - "RelayerCelerIM": "2.0.0", - "CelerIMFacetMutable": "2.0.0", - "SymbiosisFacet": "1.0.0" - } - } - }, + "arbitrumnova": {}, "zksync": { "production": { "LiFiDiamond": { @@ -561,9 +524,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -581,6 +544,7 @@ "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3", "CelerIMFacetMutable": "2.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SymbiosisFacet": "1.0.0" } } @@ -598,9 +562,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -609,12 +573,12 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0", "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SymbiosisFacet": "1.0.0" } } @@ -632,9 +596,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -643,13 +607,13 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AmarokFacet": "3.0.0", "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3", "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", "HopFacetOptimized": "2.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", "ReceiverStargateV2": "1.0.0", @@ -670,9 +634,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -695,6 +659,7 @@ "HopFacet": "2.0.0", "HopFacetPacked": "1.0.6", "HopFacetOptimized": "2.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", "ReceiverStargateV2": "1.0.0", @@ -715,9 +680,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -725,8 +690,7 @@ "Receiver": "2.0.2", "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0" + "LiFiDEXAggregator": "1.0.0" } } }, @@ -743,9 +707,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -754,7 +718,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AmarokFacet": "3.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -776,9 +739,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -787,7 +750,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AcrossFacet": "2.0.0", "AcrossFacetPacked": "1.0.0", "AcrossFacetV3": "1.0.0", @@ -795,6 +757,7 @@ "ReceiverAcrossV3": "1.0.0", "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", "ReceiverStargateV2": "1.0.0", @@ -815,9 +778,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -826,13 +789,13 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AcrossFacet": "2.0.0", "AcrossFacetPacked": "1.0.0", "AcrossFacetV3": "1.0.0", "AcrossFacetPackedV3": "1.0.0", "ReceiverAcrossV3": "1.0.0", "AmarokFacet": "3.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SymbiosisFacet": "1.0.0" } } @@ -850,9 +813,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -861,7 +824,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "SquidFacet": "1.0.0", "StargateFacet": "2.2.0", "StargateFacetV2": "1.0.1", @@ -883,9 +845,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -913,9 +875,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -932,13 +894,13 @@ "ReceiverAcrossV3": "1.0.0", "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", "SquidFacet": "1.0.0", "SymbiosisFacet": "1.0.0" } } }, - "rootstock": {}, - "sei": { + "rootstock": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -951,9 +913,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -962,15 +924,11 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", - "SquidFacet": "1.0.0", - "StargateFacetV2": "1.0.1", - "ReceiverStargateV2": "1.0.0", "SymbiosisFacet": "1.0.0" } } }, - "fraxtal": { + "sei": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -983,9 +941,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -994,8 +952,9 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "SquidFacet": "1.0.0", + "StargateFacetV2": "1.0.1", + "ReceiverStargateV2": "1.0.0", "SymbiosisFacet": "1.0.0" } } @@ -1013,9 +972,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1024,7 +983,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "StargateFacetV2": "1.0.1", "ReceiverStargateV2": "1.0.0", "SymbiosisFacet": "1.0.0" @@ -1044,9 +1002,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1055,7 +1013,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3", "RelayerCelerIM": "2.0.0", @@ -1078,9 +1035,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1089,7 +1046,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "SquidFacet": "1.0.0" } } @@ -1107,9 +1063,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1118,7 +1074,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0" } @@ -1137,9 +1092,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1147,8 +1102,7 @@ "Receiver": "2.0.2", "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0" + "LiFiDEXAggregator": "1.0.0" } } }, @@ -1165,9 +1119,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1176,7 +1130,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0" } @@ -1195,9 +1148,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1206,7 +1159,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "RelayerCelerIM": "2.0.0", "CelerIMFacetMutable": "2.0.0" } @@ -1225,9 +1177,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1235,8 +1187,7 @@ "Receiver": "2.0.2", "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0" + "LiFiDEXAggregator": "1.0.0" } } }, @@ -1253,9 +1204,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1264,7 +1215,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3", "RelayerCelerIM": "2.0.0", @@ -1287,9 +1237,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1298,7 +1248,6 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "CBridgeFacet": "1.0.0", "CBridgeFacetPacked": "1.0.3" } @@ -1317,21 +1266,21 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", "FeeCollector": "1.0.0", "Receiver": "2.0.2", "LiFuelFeeCollector": "1.0.1", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0" + "LiFiDEXAggregator": "1.0.0" } } }, - "rootstocks": { + "rootstocks": {}, + "cronos": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -1344,9 +1293,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1354,13 +1303,11 @@ "Receiver": "2.0.2", "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", - "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", - "SymbiosisFacet": "1.0.0" + "LiFiDEXAggregator": "1.0.0" } } }, - "cronos": { + "worldchain": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -1373,9 +1320,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1384,11 +1331,14 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0" + "AcrossFacetV3": "1.0.0", + "AcrossFacetPackedV3": "1.0.0", + "ReceiverAcrossV3": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m" } } }, - "worldchain": { + "lisk": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -1401,9 +1351,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1412,14 +1362,13 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AcrossFacetV3": "1.0.0", "AcrossFacetPackedV3": "1.0.0", "ReceiverAcrossV3": "1.0.0" } } }, - "lisk": { + "abstract": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -1432,9 +1381,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1443,14 +1392,16 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", "AcrossFacetV3": "1.0.0", "AcrossFacetPackedV3": "1.0.0", - "ReceiverAcrossV3": "1.0.0" + "ReceiverAcrossV3": "1.0.0", + "RelayFacet": "\u001b[31m[error] the following filepath is invalid: \u001b[31m[error] could not find src FILE path for contract RelayFacet\u001b[0m\u001b[0m", + "StargateFacetV2": "1.0.1", + "ReceiverStargateV2": "1.0.1" } } }, - "abstract": { + "fraxtal": { "production": { "LiFiDiamond": { "DiamondCutFacet": "1.0.0", @@ -1463,9 +1414,9 @@ "GenericSwapFacet": "1.0.0", "GenericSwapFacetV3": "1.0.1", "LIFuelFacet": "1.0.1", - "CalldataVerificationFacet": "1.1.1", + "CalldataVerificationFacet": "1.1.2", "StandardizedCallFacet": "1.1.0", - "EmergencyPauseFacet": "1.0.0", + "EmergencyPauseFacet": "1.0.1", "LiFiDiamond": "1.0.0", "ERC20Proxy": "1.0.0", "Executor": "2.0.0", @@ -1474,13 +1425,9 @@ "LiFuelFeeCollector": "1.0.1", "TokenWrapper": "1.0.0", "LiFiDEXAggregator": "1.0.0", - "Permit2Proxy": "1.0.0", - "AcrossFacetV3": "1.0.0", - "AcrossFacetPackedV3": "1.0.0", - "ReceiverAcrossV3": "1.0.0", - "StargateFacetV2": "1.0.1", - "ReceiverStargateV2": "1.0.1" + "SquidFacet": "1.0.0", + "SymbiosisFacet": "1.0.0" } } } -} \ No newline at end of file +} diff --git a/script/deploy/deploySingleContract.sh b/script/deploy/deploySingleContract.sh index 3209b0a49..15449095d 100755 --- a/script/deploy/deploySingleContract.sh +++ b/script/deploy/deploySingleContract.sh @@ -96,7 +96,7 @@ deploySingleContract() { if [[ $NETWORK == "zksync" ]]; then DEPLOY_SCRIPT_DIRECTORY="script/deploy/zksync/" fi - + if [[ -z "$CONTRACT" ]]; then # get user-selected deploy script and contract from list SCRIPT=$(ls -1 "$DEPLOY_SCRIPT_DIRECTORY" | sed -e 's/\.s.sol$//' | grep 'Deploy' | gum filter --placeholder "Deploy Script") @@ -225,10 +225,10 @@ deploySingleContract() { if [[ $NETWORK == "zksync" ]]; then # Deploy zksync scripts using the zksync specific fork of forge from Docker - RAW_RETURN_DATA=$(docker run --rm -it --volume .:/foundry -u $(id -u):$(id -g) -e FOUNDRY_PROFILE=zksync -e DEPLOYSALT=$DEPLOYSALT -e NETWORK=$NETWORK -e FILE_SUFFIX=$FILE_SUFFIX -e PRIVATE_KEY=$(getPrivateKey "$NETWORK" "$ENVIRONMENT") foundry-zksync forge script "$FULL_SCRIPT_PATH" -f $NETWORK --json --silent --broadcast --skip-simulation --slow --zksync) + RAW_RETURN_DATA=$(docker run --rm -it --volume .:/foundry -u $(id -u):$(id -g) -e FOUNDRY_PROFILE=zksync -e DEPLOYSALT=$DEPLOYSALT -e NETWORK=$NETWORK -e FILE_SUFFIX=$FILE_SUFFIX -e PRIVATE_KEY=$(getPrivateKey "$NETWORK" "$ENVIRONMENT") foundry-zksync forge script "$FULL_SCRIPT_PATH" -f $NETWORK --json --silent --broadcast --skip-simulation --slow --zksync) else # try to execute call - RAW_RETURN_DATA=$(DEPLOYSALT=$DEPLOYSALT CREATE3_FACTORY_ADDRESS=$CREATE3_FACTORY_ADDRESS NETWORK=$NETWORK FILE_SUFFIX=$FILE_SUFFIX DEFAULT_DIAMOND_ADDRESS_DEPLOYSALT=$DEFAULT_DIAMOND_ADDRESS_DEPLOYSALT DEPLOY_TO_DEFAULT_DIAMOND_ADDRESS=$DEPLOY_TO_DEFAULT_DIAMOND_ADDRESS PRIVATE_KEY=$(getPrivateKey "$NETWORK" "$ENVIRONMENT") DIAMOND_TYPE=$DIAMOND_TYPE forge script "$FULL_SCRIPT_PATH" -f $NETWORK -vvvvvv --json --silent --broadcast --skip-simulation --legacy) + RAW_RETURN_DATA=$(DEPLOYSALT=$DEPLOYSALT CREATE3_FACTORY_ADDRESS=$CREATE3_FACTORY_ADDRESS NETWORK=$NETWORK FILE_SUFFIX=$FILE_SUFFIX DEFAULT_DIAMOND_ADDRESS_DEPLOYSALT=$DEFAULT_DIAMOND_ADDRESS_DEPLOYSALT DEPLOY_TO_DEFAULT_DIAMOND_ADDRESS=$DEPLOY_TO_DEFAULT_DIAMOND_ADDRESS PRIVATE_KEY=$(getPrivateKey "$NETWORK" "$ENVIRONMENT") DIAMOND_TYPE=$DIAMOND_TYPE forge script "$FULL_SCRIPT_PATH" -f $NETWORK --json --broadcast --skip-simulation --legacy) fi RETURN_CODE=$? diff --git a/script/deploy/facets/DeployPermit2Proxy.s.sol b/script/deploy/facets/DeployPermit2Proxy.s.sol new file mode 100644 index 000000000..d1553cd3e --- /dev/null +++ b/script/deploy/facets/DeployPermit2Proxy.s.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.17; + +import { DeployScriptBase } from "./utils/DeployScriptBase.sol"; +import { Permit2Proxy } from "lifi/Periphery/Permit2Proxy.sol"; +import { stdJson } from "forge-std/Script.sol"; + +contract DeployScript is DeployScriptBase { + using stdJson for string; + + constructor() DeployScriptBase("Permit2Proxy") {} + + function run() + public + returns (Permit2Proxy deployed, bytes memory constructorArgs) + { + constructorArgs = getConstructorArgs(); + + deployed = Permit2Proxy(deploy(type(Permit2Proxy).creationCode)); + } + + function getConstructorArgs() internal override returns (bytes memory) { + // get the address of the LiFiDiamond for the given network + string memory deployments = string.concat( + root, + "/deployments/", + network, + ".", + fileSuffix, + "json" + ); + string memory deploymentsJSON = vm.readFile(deployments); + + address diamond = deploymentsJSON.readAddress(".LiFiDiamond"); + + // get the Permit2 contract address for the given network + string memory permit2ProxyConfig = string.concat( + root, + "/config/permit2Proxy.json" + ); + + string memory permit2ProxyConfigJSON = vm.readFile(permit2ProxyConfig); + + address permit2Address = permit2ProxyConfigJSON.readAddress( + string.concat(".", network) + ); + + // get the multisig SAFE address for the given network + string memory networksConfig = string.concat( + root, + "/config/networks.json" + ); + + string memory networksConfigJSON = vm.readFile(networksConfig); + + address safeAddress = networksConfigJSON.readAddress( + string.concat(".", network, ".safeAddress") + ); + + return abi.encode(diamond, permit2Address, safeAddress); + } +} diff --git a/script/deploy/resources/deployRequirements.json b/script/deploy/resources/deployRequirements.json index 4d512122d..2fd4bda7c 100644 --- a/script/deploy/resources/deployRequirements.json +++ b/script/deploy/resources/deployRequirements.json @@ -523,5 +523,14 @@ "allowToDeployWithZeroAddress": "false" } } + }, + "Permit2Proxy": { + "configData": { + "permit2Address": { + "configFileName": "permit2Proxy.json", + "keyInConfigFile": ".", + "allowToDeployWithZeroAddress": "false" + } + } } -} +} \ No newline at end of file diff --git a/script/deploy/safe/config.ts b/script/deploy/safe/config.ts index fb126af69..4cd557907 100644 --- a/script/deploy/safe/config.ts +++ b/script/deploy/safe/config.ts @@ -6,7 +6,7 @@ export const safeApiUrls: Record = { aurora: 'https://safe-transaction-aurora.safe.global/api', avalanche: 'https://safe-transaction-avalanche.safe.global/api', base: 'https://safe-transaction-base.safe.global/api', - blast: 'https://transaction.blast-safe.io/api', + blast: 'https://safe-transaction-blast.safe.global/api', boba: 'https://safe-transaction.mainnet.boba.network/api', bsc: 'https://safe-transaction-bsc.safe.global/api', celo: 'https://safe-transaction-celo.safe.global/api', diff --git a/script/deploy/zksync/DeployPermit2Proxy.s.sol b/script/deploy/zksync/DeployPermit2Proxy.s.sol new file mode 100644 index 000000000..d1553cd3e --- /dev/null +++ b/script/deploy/zksync/DeployPermit2Proxy.s.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.17; + +import { DeployScriptBase } from "./utils/DeployScriptBase.sol"; +import { Permit2Proxy } from "lifi/Periphery/Permit2Proxy.sol"; +import { stdJson } from "forge-std/Script.sol"; + +contract DeployScript is DeployScriptBase { + using stdJson for string; + + constructor() DeployScriptBase("Permit2Proxy") {} + + function run() + public + returns (Permit2Proxy deployed, bytes memory constructorArgs) + { + constructorArgs = getConstructorArgs(); + + deployed = Permit2Proxy(deploy(type(Permit2Proxy).creationCode)); + } + + function getConstructorArgs() internal override returns (bytes memory) { + // get the address of the LiFiDiamond for the given network + string memory deployments = string.concat( + root, + "/deployments/", + network, + ".", + fileSuffix, + "json" + ); + string memory deploymentsJSON = vm.readFile(deployments); + + address diamond = deploymentsJSON.readAddress(".LiFiDiamond"); + + // get the Permit2 contract address for the given network + string memory permit2ProxyConfig = string.concat( + root, + "/config/permit2Proxy.json" + ); + + string memory permit2ProxyConfigJSON = vm.readFile(permit2ProxyConfig); + + address permit2Address = permit2ProxyConfigJSON.readAddress( + string.concat(".", network) + ); + + // get the multisig SAFE address for the given network + string memory networksConfig = string.concat( + root, + "/config/networks.json" + ); + + string memory networksConfigJSON = vm.readFile(networksConfig); + + address safeAddress = networksConfigJSON.readAddress( + string.concat(".", network, ".safeAddress") + ); + + return abi.encode(diamond, permit2Address, safeAddress); + } +} diff --git a/src/Periphery/Permit2Proxy.sol b/src/Periphery/Permit2Proxy.sol new file mode 100644 index 000000000..ca82ae5bc --- /dev/null +++ b/src/Periphery/Permit2Proxy.sol @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import { ISignatureTransfer } from "permit2/interfaces/ISignatureTransfer.sol"; +import { LibAsset, IERC20 } from "lifi/Libraries/LibAsset.sol"; +import { PermitHash } from "permit2/libraries/PermitHash.sol"; +import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import { WithdrawablePeriphery } from "lifi/Helpers/WithdrawablePeriphery.sol"; + +/// @title Permit2Proxy +/// @author LI.FI (https://li.fi) +/// @notice Proxy contract allowing gasless calls via Permit2 as well as making +/// token approvals via ERC20 Permit (EIP-2612) to our diamond contract +/// @custom:version 1.0.0 +contract Permit2Proxy is WithdrawablePeriphery { + /// Storage /// + + address public immutable LIFI_DIAMOND; + ISignatureTransfer public immutable PERMIT2; + + string public constant WITNESS_TYPE_STRING = + "LiFiCall witness)LiFiCall(address diamondAddress,bytes32 diamondCalldataHash)TokenPermissions(address token,uint256 amount)"; + bytes32 public constant WITNESS_TYPEHASH = + keccak256( + "LiFiCall(address diamondAddress,bytes32 diamondCalldataHash)" + ); + bytes32 public immutable PERMIT_WITH_WITNESS_TYPEHASH; + + /// Types /// + + // @dev LIFI Specific Witness which verifies the correct calldata and + // diamond address + struct LiFiCall { + address diamondAddress; + bytes32 diamondCalldataHash; + } + + /// Errors /// + + error CallToDiamondFailed(bytes); + + /// Constructor /// + + constructor( + address _lifiDiamond, + ISignatureTransfer _permit2, + address _owner + ) WithdrawablePeriphery(_owner) { + LIFI_DIAMOND = _lifiDiamond; + PERMIT2 = _permit2; + + PERMIT_WITH_WITNESS_TYPEHASH = keccak256( + abi.encodePacked( + PermitHash._PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, + WITNESS_TYPE_STRING + ) + ); + } + + /// External Functions /// + + /// @notice Allows to bridge tokens through a LI.FI diamond contract using + /// an EIP2612 gasless permit (only works with tokenAddresses that + /// implement EIP2612) + /// The permit signer must be the caller to prevent front-running and ensure + /// the calldata cannot be replaced by others. + /// Can only be called by the permit signer to prevent front-running. + /// @param tokenAddress Address of the token to be bridged + /// @param amount Amount of tokens to be bridged + /// @param deadline Transaction must be completed before this timestamp + /// @param v User signature (recovery ID) + /// @param r User signature (ECDSA output) + /// @param s User signature (ECDSA output) + /// @param diamondCalldata calldata to execute + function callDiamondWithEIP2612Signature( + address tokenAddress, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s, + bytes calldata diamondCalldata + ) public payable returns (bytes memory) { + // call permit on token contract to register approval using signature + ERC20Permit(tokenAddress).permit( + msg.sender, // Ensure msg.sender is same wallet that signed permit + address(this), + amount, + deadline, + v, + r, + s + ); + + // deposit assets + LibAsset.transferFromERC20( + tokenAddress, + msg.sender, + address(this), + amount + ); + + // maxApprove token to diamond if current allowance is insufficient + LibAsset.maxApproveERC20(IERC20(tokenAddress), LIFI_DIAMOND, amount); + + // call our diamond to execute calldata + return _executeCalldata(diamondCalldata); + } + + /// @notice Allows to bridge tokens of one type through a LI.FI diamond + /// contract using Uniswap's Permit2 contract and a user signature + /// that verifies allowance. The permit signer must be the caller to prevent front-running and + /// ensure the calldata cannot be replaced by others. Can only be called by the permit signer to prevent + /// front-running. + /// @param _diamondCalldata the calldata to execute + /// @param _permit the Uniswap Permit2 parameters + /// @param _signature the signature giving approval to transfer tokens + function callDiamondWithPermit2( + bytes calldata _diamondCalldata, + ISignatureTransfer.PermitTransferFrom calldata _permit, + bytes calldata _signature + ) external payable returns (bytes memory) { + PERMIT2.permitTransferFrom( + _permit, + ISignatureTransfer.SignatureTransferDetails({ + to: address(this), + requestedAmount: _permit.permitted.amount + }), + msg.sender, // Ensure msg.sender is same wallet that signed permit + _signature + ); + + // maxApprove token to diamond if current allowance is insufficient + LibAsset.maxApproveERC20( + IERC20(_permit.permitted.token), + LIFI_DIAMOND, + _permit.permitted.amount + ); + + return _executeCalldata(_diamondCalldata); + } + + /// @notice Allows to bridge tokens of one type through a LI.FI diamond + /// contract using Uniswap's Permit2 contract and a user signature + /// that verifies allowance, diamondAddress and diamondCalldata + /// @param _diamondCalldata the calldata to execute + /// @param _signer the signer giving permission to transfer tokens + /// @param _permit the Uniswap Permit2 parameters + /// @param _signature the signature giving approval to transfer tokens + function callDiamondWithPermit2Witness( + bytes calldata _diamondCalldata, + address _signer, + ISignatureTransfer.PermitTransferFrom calldata _permit, + bytes calldata _signature + ) external payable returns (bytes memory) { + LiFiCall memory lifiCall = LiFiCall( + LIFI_DIAMOND, + keccak256(_diamondCalldata) + ); + + bytes32 witness = keccak256(abi.encode(WITNESS_TYPEHASH, lifiCall)); + + PERMIT2.permitWitnessTransferFrom( + _permit, + ISignatureTransfer.SignatureTransferDetails({ + to: address(this), + requestedAmount: _permit.permitted.amount + }), + _signer, + witness, + WITNESS_TYPE_STRING, + _signature + ); + + // maxApprove token to diamond if current allowance is insufficient + LibAsset.maxApproveERC20( + IERC20(_permit.permitted.token), + LIFI_DIAMOND, + _permit.permitted.amount + ); + + return _executeCalldata(_diamondCalldata); + } + + /// @notice utitlity method for constructing a valid Permit2 message hash + /// @param _diamondCalldata the calldata to execute + /// @param _assetId the address of the token to approve + /// @param _amount amount of tokens to approve + /// @param _nonce the nonce to use + /// @param _deadline the expiration deadline + function getPermit2MsgHash( + bytes calldata _diamondCalldata, + address _assetId, + uint256 _amount, + uint256 _nonce, + uint256 _deadline + ) external view returns (bytes32 msgHash) { + // Token Permissions + ISignatureTransfer.TokenPermissions + memory tokenPermissions = ISignatureTransfer.TokenPermissions( + _assetId, + _amount + ); + bytes32 permit = _getTokenPermissionsHash(tokenPermissions); + + // Witness + Permit2Proxy.LiFiCall memory lifiCall = LiFiCall( + LIFI_DIAMOND, + keccak256(_diamondCalldata) + ); + bytes32 witness = _getWitnessHash(lifiCall); + + // PermitTransferWithWitness + msgHash = _getPermitWitnessTransferFromHash( + PERMIT2.DOMAIN_SEPARATOR(), + permit, + address(this), + _nonce, + _deadline, + witness + ); + } + + /// Internal Functions /// + + function _getTokenPermissionsHash( + ISignatureTransfer.TokenPermissions memory tokenPermissions + ) internal pure returns (bytes32) { + return + keccak256( + abi.encode( + PermitHash._TOKEN_PERMISSIONS_TYPEHASH, + tokenPermissions.token, + tokenPermissions.amount + ) + ); + } + + function _getWitnessHash( + Permit2Proxy.LiFiCall memory lifiCall + ) internal pure returns (bytes32) { + return keccak256(abi.encode(WITNESS_TYPEHASH, lifiCall)); + } + + function _getPermitWitnessTransferFromHash( + bytes32 domainSeparator, + bytes32 permit, + address spender, + uint256 nonce, + uint256 deadline, + bytes32 witness + ) internal view returns (bytes32) { + bytes32 dataHash = keccak256( + abi.encode( + PERMIT_WITH_WITNESS_TYPEHASH, + permit, + spender, + nonce, + deadline, + witness + ) + ); + + return + keccak256(abi.encodePacked("\x19\x01", domainSeparator, dataHash)); + } + + function _executeCalldata( + bytes memory diamondCalldata + ) internal returns (bytes memory) { + // call diamond with provided calldata + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory data) = LIFI_DIAMOND.call{ + value: msg.value + }(diamondCalldata); + // throw error to make sure tx reverts if low-level call was + // unsuccessful + if (!success) { + revert CallToDiamondFailed(data); + } + return data; + } + + /// The following code was adapted from https://github.com/flood-protocol/permit2-nonce-finder/blob/7a4ac8a58d0b499308000b75ddb2384834f31fac/src/Permit2NonceFinder.sol + /// Provides utility functions for determining the next valid Permit2 nonce + + /// @notice Finds the next valid nonce for a user, starting from 0. + /// @param owner The owner of the nonces + /// @return nonce The first valid nonce starting from 0 + function nextNonce(address owner) external view returns (uint256 nonce) { + nonce = _nextNonce(owner, 0, 0); + } + + /// @notice Finds the next valid nonce for a user, after from a given nonce. + /// @dev This can be helpful if you're signing multiple nonces in a row and need the next nonce to sign but the start one is still valid. + /// @param owner The owner of the nonces + /// @param start The nonce to start from + /// @return nonce The first valid nonce after the given nonce + function nextNonceAfter( + address owner, + uint256 start + ) external view returns (uint256 nonce) { + uint248 word = uint248(start >> 8); + uint8 pos = uint8(start); + if (pos == type(uint8).max) { + // If the position is 255, we need to move to the next word + word++; + pos = 0; + } else { + // Otherwise, we just move to the next position + pos++; + } + nonce = _nextNonce(owner, word, pos); + } + + /// @notice Finds the next valid nonce for a user, starting from a given word and position. + /// @param owner The owner of the nonces + /// @param word Word to start looking from + /// @param pos Position inside the word to start looking from + function _nextNonce( + address owner, + uint248 word, + uint8 pos + ) internal view returns (uint256 nonce) { + while (true) { + uint256 bitmap = PERMIT2.nonceBitmap(owner, word); + + // Check if the bitmap is completely full + if (bitmap == type(uint256).max) { + // If so, move to the next word + ++word; + pos = 0; + continue; + } + if (pos != 0) { + // If the position is not 0, we need to shift the bitmap to ignore the bits before position + bitmap = bitmap >> pos; + } + // Find the first zero bit in the bitmap + while (bitmap & 1 == 1) { + bitmap = bitmap >> 1; + ++pos; + } + + return _nonceFromWordAndPos(word, pos); + } + } + + /// @notice Constructs a nonce from a word and a position inside the word + /// @param word The word containing the nonce + /// @param pos The position of the nonce inside the word + /// @return nonce The nonce constructed from the word and position + function _nonceFromWordAndPos( + uint248 word, + uint8 pos + ) internal pure returns (uint256 nonce) { + // The last 248 bits of the word are the nonce bits + nonce = uint256(word) << 8; + // The first 8 bits of the word are the position inside the word + nonce |= pos; + } + + // required to be able to receive native token refunds from the diamond + receive() external payable {} +} diff --git a/test/solidity/Periphery/Permit2Proxy.t.sol b/test/solidity/Periphery/Permit2Proxy.t.sol new file mode 100644 index 000000000..7719f2f98 --- /dev/null +++ b/test/solidity/Periphery/Permit2Proxy.t.sol @@ -0,0 +1,719 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import { TestBase, ILiFi, console, ERC20 } from "../utils/TestBase.sol"; +import { Permit2Proxy } from "lifi/Periphery/Permit2Proxy.sol"; +import { ISignatureTransfer } from "permit2/interfaces/ISignatureTransfer.sol"; +import { PermitHash } from "permit2/libraries/PermitHash.sol"; +import { PolygonBridgeFacet } from "lifi/Facets/PolygonBridgeFacet.sol"; +import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; + +contract Permit2ProxyTest is TestBase { + using PermitHash for ISignatureTransfer.PermitTransferFrom; + + /// Constants /// + + address internal constant PERMIT2_ADDRESS = + 0x000000000022D473030F116dDEE9F6B43aC78BA3; + uint256 internal PRIVATE_KEY = 0x1234567890; + address internal DIAMOND_ADDRESS = + 0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE; + + /// Storage /// + + bytes32 internal PERMIT_WITH_WITNESS_TYPEHASH; + Permit2Proxy internal permit2Proxy; + ISignatureTransfer internal uniPermit2; + address internal PERMIT2_USER; + + /// Types /// + + struct TestDataEIP2612 { + address tokenAddress; + address userWallet; + uint256 nonce; + uint256 deadline; + bytes diamondCalldata; + uint8 v; + bytes32 r; + bytes32 s; + } + + /// Errors /// + + error InvalidSigner(); + error InvalidNonce(); + error DiamondAddressNotWhitelisted(); + error CallToDiamondFailed(bytes); + + function setUp() public { + customBlockNumberForForking = 20261175; + initTestBase(); + + uniPermit2 = ISignatureTransfer(PERMIT2_ADDRESS); + permit2Proxy = new Permit2Proxy( + DIAMOND_ADDRESS, + uniPermit2, + USER_DIAMOND_OWNER + ); + PERMIT_WITH_WITNESS_TYPEHASH = keccak256( + abi.encodePacked( + PermitHash._PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, + permit2Proxy.WITNESS_TYPE_STRING() + ) + ); + + PERMIT2_USER = vm.addr(PRIVATE_KEY); + vm.label(PERMIT2_USER, "Permit2 User"); + deal(ADDRESS_USDC, PERMIT2_USER, 10000 ether); + + // Infinite approve to Permit2 + vm.prank(PERMIT2_USER); + ERC20(ADDRESS_USDC).approve(PERMIT2_ADDRESS, type(uint256).max); + } + + /// Tests /// + + /// EIP2612 (native permit) related test cases /// + + function test_can_execute_calldata_using_eip2612_signature_usdc() + public + assertBalanceChange( + ADDRESS_USDC, + PERMIT2_USER, + -int256(defaultUSDCAmount) + ) + returns (TestDataEIP2612 memory) + { + vm.startPrank(PERMIT2_USER); + + // get token-specific domainSeparator + bytes32 domainSeparator = ERC20Permit(ADDRESS_USDC).DOMAIN_SEPARATOR(); + + // // using USDC on ETH for testing (implements EIP2612) + TestDataEIP2612 + memory testdata = _getTestDataEIP2612SignedByPERMIT2_USER( + ADDRESS_USDC, + domainSeparator, + block.timestamp + 1000 + ); + + // expect LifiTransferStarted event to be emitted by our diamond contract + vm.expectEmit(true, true, true, true, DIAMOND_ADDRESS); + emit LiFiTransferStarted(bridgeData); + + // call Permit2Proxy with signature + permit2Proxy.callDiamondWithEIP2612Signature( + ADDRESS_USDC, + defaultUSDCAmount, + testdata.deadline, + testdata.v, + testdata.r, + testdata.s, + testdata.diamondCalldata + ); + vm.stopPrank(); + return testdata; + } + + function testRevert_when_called_with_invalid_calldata() public { + vm.startPrank(PERMIT2_USER); + + // get token-specific domainSeparator + bytes32 domainSeparator = ERC20Permit(ADDRESS_USDC).DOMAIN_SEPARATOR(); + + // // using USDC on ETH for testing (implements EIP2612) + TestDataEIP2612 + memory testdata = _getTestDataEIP2612SignedByPERMIT2_USER( + ADDRESS_USDC, + domainSeparator, + block.timestamp + 1000 + ); + + // call Permit2Proxy with signature + vm.expectRevert( + abi.encodeWithSignature( + "CallToDiamondFailed(bytes)", + hex"a9ad62f8" // Function does not exist + ) + ); + permit2Proxy.callDiamondWithEIP2612Signature( + ADDRESS_USDC, + defaultUSDCAmount, + testdata.deadline, + testdata.v, + testdata.r, + testdata.s, + hex"1337c0d3" // This should revert as the method does not exist + ); + } + + function testRevert_cannot_use_eip2612_signature_twice() public { + TestDataEIP2612 + memory testdata = test_can_execute_calldata_using_eip2612_signature_usdc(); + + vm.startPrank(PERMIT2_USER); + + // // expect call to revert if same signature is used twice + vm.expectRevert("EIP2612: invalid signature"); + permit2Proxy.callDiamondWithEIP2612Signature( + ADDRESS_USDC, + defaultUSDCAmount, + testdata.deadline, + testdata.v, + testdata.r, + testdata.s, + testdata.diamondCalldata + ); + + vm.stopPrank(); + } + + function testRevert_cannot_use_expired_eip2612_signature() public { + vm.startPrank(PERMIT2_USER); + + // get token-specific domainSeparator + bytes32 domainSeparator = ERC20Permit(ADDRESS_USDC).DOMAIN_SEPARATOR(); + + // // using USDC on ETH for testing (implements EIP2612) + TestDataEIP2612 + memory testdata = _getTestDataEIP2612SignedByPERMIT2_USER( + ADDRESS_USDC, + domainSeparator, + block.timestamp - 1 // deadline in the past + ); + + // expect call to revert since signature deadline is in the past + vm.expectRevert("FiatTokenV2: permit is expired"); + + // call Permit2Proxy with signature + permit2Proxy.callDiamondWithEIP2612Signature( + ADDRESS_USDC, + defaultUSDCAmount, + testdata.deadline, + testdata.v, + testdata.r, + testdata.s, + testdata.diamondCalldata + ); + + vm.stopPrank(); + } + + function testRevert_cannot_use_invalid_eip2612_signature() public { + vm.startPrank(PERMIT2_USER); + + // get token-specific domainSeparator + bytes32 domainSeparator = ERC20Permit(ADDRESS_USDC).DOMAIN_SEPARATOR(); + + // // using USDC on ETH for testing (implements EIP2612) + TestDataEIP2612 + memory testdata = _getTestDataEIP2612SignedByPERMIT2_USER( + ADDRESS_USDC, + domainSeparator, + block.timestamp + ); + + // expect call to revert since signature is invalid + vm.expectRevert("ECRecover: invalid signature 'v' value"); + + // call Permit2Proxy with signature + permit2Proxy.callDiamondWithEIP2612Signature( + ADDRESS_USDC, + defaultUSDCAmount, + testdata.deadline, + testdata.v + 1, // invalid v value + testdata.r, + testdata.s, + testdata.diamondCalldata + ); + + vm.stopPrank(); + } + + function testRevert_sign_and_call_using_different_addresses() public { + vm.startPrank(USER_SENDER); + + // get token-specific domainSeparator + bytes32 domainSeparator = ERC20Permit(ADDRESS_USDC).DOMAIN_SEPARATOR(); + + // // using USDC on ETH for testing (implements EIP2612) + TestDataEIP2612 + memory testdata = _getTestDataEIP2612SignedByPERMIT2_USER( + ADDRESS_USDC, + domainSeparator, + block.timestamp + ); + + // expect call to revert since signature was created by a different address + vm.expectRevert("EIP2612: invalid signature"); + // call Permit2Proxy with signature + permit2Proxy.callDiamondWithEIP2612Signature( + ADDRESS_USDC, + defaultUSDCAmount, + testdata.deadline, + testdata.v, + testdata.r, + testdata.s, + testdata.diamondCalldata + ); + + vm.stopPrank(); + } + + /// Permit2 specific tests /// + + function test_user_can_call_diamond_with_own_permit2_signature() public { + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes memory signature; + ( + diamondCalldata, + permitTransferFrom, + , + signature + ) = _getPermit2TransferFromParamsSignedByPERMIT2_USER(); + + // Execute + vm.prank(PERMIT2_USER); + permit2Proxy.callDiamondWithPermit2( + diamondCalldata, + permitTransferFrom, + signature + ); + } + + function testRevert_cannot_call_diamond_with_permit2_using_different_wallet_address() + public + { + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes memory signature; + ( + diamondCalldata, + permitTransferFrom, + , + signature + ) = _getPermit2TransferFromParamsSignedByPERMIT2_USER(); + + // Execute + vm.prank(USER_SENDER); // Not the original signer + vm.expectRevert(InvalidSigner.selector); + permit2Proxy.callDiamondWithPermit2( + diamondCalldata, + permitTransferFrom, + signature + ); + } + + function test_can_call_diamond_with_permit2_plus_witness() public { + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes memory signature; + ( + diamondCalldata, + permitTransferFrom, + , + signature + ) = _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER(); + + // Execute + vm.prank(USER_SENDER); // Can be executed by anyone + permit2Proxy.callDiamondWithPermit2Witness( + diamondCalldata, + PERMIT2_USER, + permitTransferFrom, + signature + ); + } + + function test_can_generate_a_valid_msg_hash_for_signing() public { + bytes32 msgHash; + bytes32 generatedMsgHash; + ( + , + , + msgHash, + + ) = _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER(); + + generatedMsgHash = permit2Proxy.getPermit2MsgHash( + _getCalldataForBridging(), + ADDRESS_USDC, + defaultUSDCAmount, + 0, + block.timestamp + 1000 + ); + + assertEq(msgHash, generatedMsgHash); + } + + function testRevert_cannot_call_diamond_single_with_same_signature_more_than_once() + public + { + deal(ADDRESS_USDC, PERMIT2_USER, 10000 ether); + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes memory signature; + ( + diamondCalldata, + permitTransferFrom, + , + signature + ) = _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER(); + + // Execute x2 + permit2Proxy.callDiamondWithPermit2Witness( + diamondCalldata, + PERMIT2_USER, + permitTransferFrom, + signature + ); + vm.expectRevert(InvalidNonce.selector); + permit2Proxy.callDiamondWithPermit2Witness( + diamondCalldata, + PERMIT2_USER, + permitTransferFrom, + signature + ); + } + + function testRevert_cannot_set_different_calldata_than_intended() public { + deal(ADDRESS_USDC, PERMIT2_USER, 10000 ether); + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes memory signature; + ( + diamondCalldata, + permitTransferFrom, + , + signature + ) = _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER(); + + bytes memory MALICIOUS_CALLDATA = hex"1337c0d3"; + + // Execute + vm.expectRevert(InvalidSigner.selector); + permit2Proxy.callDiamondWithPermit2Witness( + MALICIOUS_CALLDATA, + PERMIT2_USER, + permitTransferFrom, + signature + ); + } + + function testRevert_cannot_use_permit2_signature_from_another_wallet() + public + { + deal(ADDRESS_USDC, PERMIT2_USER, 10000 ether); + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes32 msgHash; + ( + diamondCalldata, + permitTransferFrom, + msgHash, + + ) = _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER(); + + // Sign with a random key + bytes memory signature = _signMsgHash(msgHash, 987654321); + + // Execute + vm.expectRevert(InvalidSigner.selector); + permit2Proxy.callDiamondWithPermit2Witness( + diamondCalldata, + PERMIT2_USER, + permitTransferFrom, + signature + ); + } + + function testRevert_cannot_transfer_more_tokens_than_intended() public { + deal(ADDRESS_USDC, PERMIT2_USER, 10000 ether); + bytes memory diamondCalldata; + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom; + bytes32 msgHash; + bytes memory signature; + ( + diamondCalldata, + permitTransferFrom, + msgHash, + signature + ) = _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER(); + + permitTransferFrom.permitted.amount += 1; + + // Execute + vm.expectRevert(InvalidSigner.selector); + permit2Proxy.callDiamondWithPermit2Witness( + diamondCalldata, + PERMIT2_USER, + permitTransferFrom, + signature + ); + } + + /// The following test code was adapted from https://github.com/flood-protocol/permit2-nonce-finder/blob/7a4ac8a58d0b499308000b75ddb2384834f31fac/test/Permit2NonceFinder.t.sol + + function test_can_find_nonce() public { + // We invalidate the first nonce to make sure it's not returned. + // We pass a mask of 0...0011 to invalidate nonce 0 and 1. + uniPermit2.invalidateUnorderedNonces(0, 3); + assertEq(permit2Proxy.nextNonce(address(this)), 2); + + // Invalidate the first word minus 1 nonce + uniPermit2.invalidateUnorderedNonces(0, type(uint256).max >> 1); + // We should find the last nonce in the first word + assertEq(permit2Proxy.nextNonce(address(this)), 255); + } + + function test_can_find_nonce_after() public { + // We want to start from the second word + uint256 start = 256; + // We invalidate the whole next word to make sure it's not returned. + uniPermit2.invalidateUnorderedNonces(1, type(uint256).max); + assertEq(permit2Proxy.nextNonceAfter(address(this), start), 512); + + // Invalidate the next word minus 1 nonce + uniPermit2.invalidateUnorderedNonces(2, type(uint256).max >> 1); + // We should find the first nonce in the third word + assertEq(permit2Proxy.nextNonceAfter(address(this), 767), 768); + + // The first word is still accessible if we start from a lower nonce + assertEq(permit2Proxy.nextNonceAfter(address(this), 1), 2); + } + + /// Helper Functions /// + + function _getPermit2TransferFromParamsSignedByPERMIT2_USER() + internal + view + returns ( + bytes memory diamondCalldata, + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom, + bytes32 msgHash, + bytes memory signature + ) + { + // Calldata + diamondCalldata = _getCalldataForBridging(); + + // Token Permissions + ISignatureTransfer.TokenPermissions + memory tokenPermissions = ISignatureTransfer.TokenPermissions( + ADDRESS_USDC, + defaultUSDCAmount + ); + bytes32 permit = _getTokenPermissionsHash(tokenPermissions); + + // Nonce + uint256 nonce = permit2Proxy.nextNonce(PERMIT2_USER); + + // PermitTransferFrom + msgHash = _getPermitTransferFromHash( + uniPermit2.DOMAIN_SEPARATOR(), + permit, + address(permit2Proxy), + nonce, + block.timestamp + 1000 + ); + + signature = _signMsgHash(msgHash, PRIVATE_KEY); + + permitTransferFrom = ISignatureTransfer.PermitTransferFrom( + tokenPermissions, + nonce, + block.timestamp + 1000 + ); + } + + function _getPermit2WitnessTransferFromParamsSignedByPERMIT2_USER() + internal + view + returns ( + bytes memory diamondCalldata, + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom, + bytes32 msgHash, + bytes memory signature + ) + { + // Token Permissions + ISignatureTransfer.TokenPermissions + memory tokenPermissions = ISignatureTransfer.TokenPermissions( + ADDRESS_USDC, + defaultUSDCAmount + ); + bytes32 permit = _getTokenPermissionsHash(tokenPermissions); + + // Witness + diamondCalldata = _getCalldataForBridging(); + Permit2Proxy.LiFiCall memory lifiCall = Permit2Proxy.LiFiCall( + DIAMOND_ADDRESS, + keccak256(diamondCalldata) + ); + bytes32 witness = _getWitnessHash(lifiCall); + + // Nonce + uint256 nonce = permit2Proxy.nextNonce(PERMIT2_USER); + + // PermitTransferWithWitness + msgHash = _getPermitWitnessTransferFromHash( + uniPermit2.DOMAIN_SEPARATOR(), + permit, + address(permit2Proxy), + nonce, + block.timestamp + 1000, + witness + ); + + signature = _signMsgHash(msgHash, PRIVATE_KEY); + + permitTransferFrom = ISignatureTransfer.PermitTransferFrom( + tokenPermissions, + nonce, + block.timestamp + 1000 + ); + } + + function _signMsgHash( + bytes32 msgHash, + uint256 privateKey + ) internal pure returns (bytes memory signature) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, msgHash); + signature = bytes.concat(r, s, bytes1(v)); + } + + function _getCalldataForBridging() + private + view + returns (bytes memory diamondCalldata) + { + bytes4 selector = PolygonBridgeFacet + .startBridgeTokensViaPolygonBridge + .selector; + + diamondCalldata = abi.encodeWithSelector(selector, bridgeData); + } + + function _getTokenPermissionsHash( + ISignatureTransfer.TokenPermissions memory tokenPermissions + ) internal pure returns (bytes32) { + return + keccak256( + abi.encode( + PermitHash._TOKEN_PERMISSIONS_TYPEHASH, + tokenPermissions.token, + tokenPermissions.amount + ) + ); + } + + function _getWitnessHash( + Permit2Proxy.LiFiCall memory lifiCall + ) internal view returns (bytes32) { + return + keccak256(abi.encode(permit2Proxy.WITNESS_TYPEHASH(), lifiCall)); + } + + function _getPermitTransferFromHash( + bytes32 domainSeparator, + bytes32 permit, + address spender, + uint256 nonce, + uint256 deadline + ) internal pure returns (bytes32) { + bytes32 dataHash = keccak256( + abi.encode( + PermitHash._PERMIT_TRANSFER_FROM_TYPEHASH, + permit, + spender, + nonce, + deadline + ) + ); + + return + keccak256(abi.encodePacked("\x19\x01", domainSeparator, dataHash)); + } + + function _getPermitWitnessTransferFromHash( + bytes32 domainSeparator, + bytes32 permit, + address spender, + uint256 nonce, + uint256 deadline, + bytes32 witness + ) internal view returns (bytes32) { + bytes32 dataHash = keccak256( + abi.encode( + PERMIT_WITH_WITNESS_TYPEHASH, + permit, + spender, + nonce, + deadline, + witness + ) + ); + + return + keccak256(abi.encodePacked("\x19\x01", domainSeparator, dataHash)); + } + + function _getTestDataEIP2612SignedByPERMIT2_USER( + address tokenAddress, + bytes32 domainSeparator, + uint256 deadline + ) internal view returns (TestDataEIP2612 memory testdata) { + testdata.tokenAddress = tokenAddress; + testdata.userWallet = PERMIT2_USER; + testdata.nonce = ERC20Permit(tokenAddress).nonces(testdata.userWallet); + testdata.deadline = deadline; + + // generate approval data to be signed by user + bytes32 digest = _generateEIP2612MsgHash( + testdata.userWallet, + address(permit2Proxy), + defaultUSDCAmount, + testdata.nonce, + testdata.deadline, + domainSeparator + ); + + // sign digest and return signature + (testdata.v, testdata.r, testdata.s) = vm.sign(PRIVATE_KEY, digest); + + // get calldata for bridging (simple USDC bridging via PolygonBridge) + testdata.diamondCalldata = _getCalldataForBridging(); + } + + function _generateEIP2612MsgHash( + address owner, + address spender, + uint256 amount, + uint256 nonce, + uint256 deadline, + bytes32 domainSeparator + ) internal pure returns (bytes32 digest) { + digest = keccak256( + abi.encodePacked( + "\x19\x01", + // Domain separator + domainSeparator, + // Permit struct + keccak256( + abi.encode( + keccak256( + "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" + ), + owner, + spender, + amount, + nonce, + deadline + ) + ) + ) + ); + } +} diff --git a/tsconfig.json b/tsconfig.json index 9481593ca..537531a02 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es2020", "module": "commonjs", "strict": true, "esModuleInterop": true, @@ -8,7 +8,7 @@ "forceConsistentCasingInFileNames": true, "outDir": "dist", "resolveJsonModule": true, - "lib": ["es2015", "DOM"], + "lib": ["es2020", "DOM"], "types": ["node"] }, "include": [ diff --git a/yarn.lock b/yarn.lock index 44669d7ea..0f30a8f38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2090,6 +2090,14 @@ immer "^9.0.7" lodash-es "^4.17.21" +"@uniswap/permit2-sdk@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@uniswap/permit2-sdk/-/permit2-sdk-1.3.0.tgz#b54124e570f0adbaca9d39b2de3054fd7d3798a1" + integrity sha512-LstYQWP47dwpQrgqBJ+ysFstne9LgI5FGiKHc2ewjj91MTY8Mq1reocu6U/VDncdR5ef30TUOcZ7gPExRY8r6Q== + dependencies: + ethers "^5.7.0" + tiny-invariant "^1.1.0" + "@uniswap/sdk@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@uniswap/sdk/-/sdk-3.0.3.tgz#8201c7c72215d0030cb99acc7e661eff895c18a9"