Skip to content

integrate 0x v2 #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 49 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c66e398
integrate 0x v2
mintdart Jun 13, 2024
c858fe7
use a different button for signing swap
mintdart Jun 13, 2024
fbf382e
update query params
mintdart Jun 14, 2024
7c473f6
update query params
mintdart Jun 14, 2024
22ca0c8
update query params
mintdart Jun 14, 2024
7fee618
update aggregator name and supported chains
mintdart Jun 20, 2024
9112df4
remove allowanceTarget check
mintdart Jun 24, 2024
c77f0d3
fix slippageBps
mintdart Jun 26, 2024
a11fc47
handle native tokens swap
mintdart Jun 27, 2024
6394919
hardcode approval address
mintdart Jun 30, 2024
7c9a89a
fixes
mintdart Jul 3, 2024
e6065fe
Merge branch 'master' into 0x-v2
mintdart Jul 31, 2024
d893bfc
integrate allowance-holder api
mintdart Jul 31, 2024
a2d40ce
fix
mintdart Jul 31, 2024
04ed99a
update chains and refactor allowance code
mintdart Aug 1, 2024
f7928bc
update api key
mintdart Aug 1, 2024
7c1b013
use a constant instead and label clearly
0xngmi Sep 27, 2024
01c28be
remove infinite approval from v2 for now
0xngmi Sep 27, 2024
c98f50b
add support for more chains and disable v1
mintdart Sep 28, 2024
0a178ef
update comment
mintdart Sep 28, 2024
6812ae4
update signature
mintdart Sep 28, 2024
f6dc46d
fix
mintdart Sep 28, 2024
33c1f7e
fix
mintdart Sep 28, 2024
a17aa56
fix
mintdart Sep 28, 2024
dca5bd9
disable allowance api
mintdart Sep 28, 2024
63a4302
fix
mintdart Sep 28, 2024
02939bb
rename
mintdart Oct 1, 2024
cb53a25
test
mintdart Oct 1, 2024
fea71bd
Revert "test"
mintdart Oct 1, 2024
5c2d160
Merge branch 'master' into 0x-v2
mintdart Dec 7, 2024
bba1867
Update getAllowance.ts
mintdart Dec 7, 2024
662d2e1
migrate from ethers
mintdart Dec 7, 2024
6bc60a3
fix
mintdart Dec 7, 2024
137948a
refactor
mintdart Dec 7, 2024
1f9c6d5
update supported chains list
mintdart Dec 7, 2024
0bb147e
test
mintdart Dec 7, 2024
3c83410
Revert "test"
mintdart Dec 7, 2024
b5714d2
refactor
mintdart Dec 7, 2024
3a6fab6
Merge branch 'master' into 0x-v2
0xngmi May 1, 2025
d08e01f
fix chain id
0xngmi May 1, 2025
1805e63
fix unused imports
0xngmi May 1, 2025
38617f0
fix
mintdart May 1, 2025
3040cb0
fix
mintdart May 1, 2025
282ab62
fix
mintdart May 1, 2025
66e7cac
refactor
mintdart May 1, 2025
694f60e
use mutation key
mintdart May 1, 2025
00abc59
Revert "use mutation key"
mintdart May 1, 2025
3a8ca8d
add support to charge fees in api
mintdart May 2, 2025
d9a64bb
Revert "add support to charge fees in api"
mintdart May 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/components/Aggregator/adapters/0x.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import BigNumber from 'bignumber.js';
import { defillamaReferrerAddress } from '../constants';
import { sendTx } from '../utils/sendTx';
import { zeroAddress } from 'viem';
Expand Down
115 changes: 115 additions & 0 deletions src/components/Aggregator/adapters/0xV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { numberToHex, size, zeroAddress, concat} from 'viem';
import { sendTx } from '../utils/sendTx';

export const name = 'Matcha/0x v2';
export const token = 'ZRX';
export const isOutputAvailable = false;

export const chainToId = {
ethereum: '1',
bsc: '56',
polygon: '137',
optimism: '10',
arbitrum: '42161',
avax: '43114',
base: '8453',
linea: '59144',
scroll: '534352',
blast: '81457',
mantle: '5000',
mode: '34443'
// missing unichain
};

const nativeToken = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
const feeCollectorAddress = '0x9Ab6164976514F1178E2BB4219DA8700c9D96E9A';
const permit2Address = '0x000000000022d473030f116ddee9f6b43ac78ba3';

export async function getQuote(chain: string, from: string, to: string, amount: string, extra) {
// amount should include decimals

const tokenFrom = from === zeroAddress ? nativeToken : from;
const tokenTo = to === zeroAddress ? nativeToken : to;

if (extra.amountOut && extra.amountOut !== '0') {
throw new Error('Invalid query params');
}

const amountParam = `sellAmount=${amount}`;

const taker = extra.userAddress === zeroAddress ? '0x1000000000000000000000000000000000000000' : extra.userAddress;

// only expects integer
const slippage = (extra.slippage * 100) | 0;

const data = await fetch(
`https://api.0x.org/swap/permit2/quote?chainId=${chainToId[chain]}&buyToken=${tokenTo}&${amountParam}&sellToken=${tokenFrom}&slippageBps=${slippage}&taker=${taker}&tradeSurplusRecipient=${feeCollectorAddress}`,
{
headers: {
'0x-api-key': process.env.OX_API_KEY as string,
'0x-version': 'v2'
}
}
).then(async (r) => {
if (r.status !== 200) {
throw new Error('Failed to fetch');
}

const data = await r.json();

return data;
});

if (
data.permit2 !== null &&
data.permit2.eip712.domain.verifyingContract.toLowerCase() !== permit2Address.toLowerCase()
) {
throw new Error(`Approval address does not match`);
}

return {
amountReturned: data?.buyAmount || 0,
amountIn: data?.sellAmount || 0,
tokenApprovalAddress: permit2Address,
estimatedGas: data.transaction.gas,
rawQuote: { ...data, gasLimit: data.transaction.gas },
isSignatureNeededForSwap: true,
logo: 'https://www.gitbook.com/cdn-cgi/image/width=40,height=40,fit=contain,dpr=2,format=auto/https%3A%2F%2F1690203644-files.gitbook.io%2F~%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FKX9pG8rH3DbKDOvV7di7%252Ficon%252F1nKfBhLbPxd2KuXchHET%252F0x%2520logo.png%3Falt%3Dmedia%26token%3D25a85a3e-7f72-47ea-a8b2-e28c0d24074b'
};
}

export async function signatureForSwap({ rawQuote, signTypedDataAsync }) {
const signature = await signTypedDataAsync(rawQuote.permit2.eip712).catch((err) => {
console.log(err)
});
return signature;
}

export async function swap({ fromAddress, rawQuote, signature }) {
// signature not needed if using allowance holder api
const signatureLengthInHex = signature
? numberToHex(size(signature), {
signed: false,
size: 32
})
: null;
const data = signature
? concat([rawQuote.transaction.data, signatureLengthInHex, signature])
: rawQuote.transaction.data;
const tx = await sendTx({
from: fromAddress,
to: rawQuote.transaction.to,
data,
value: rawQuote.transaction.value
});

return tx;
}

export const getTxData = ({ rawQuote }) => rawQuote?.transaction?.data;

export const getTx = ({ rawQuote }) => ({
to: rawQuote.transaction.to,
data: rawQuote.transaction.data,
value: rawQuote.transaction.value
});
1 change: 0 additions & 1 deletion src/components/Aggregator/adapters/openocean.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import BigNumber from 'bignumber.js';
import { sendTx } from '../utils/sendTx';
import { zeroAddress } from 'viem';

Expand Down
2 changes: 1 addition & 1 deletion src/components/Aggregator/hooks/useEstimateGas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const estimateGas = async ({
!Number.isFinite(balance) ||
balance < +route.fromAmount ||
!route.price ||
!traceRpcs[chain]
!traceRpcs[chain] || route.name === 'Matcha/0x v2'
) {
return null;
}
Expand Down
43 changes: 3 additions & 40 deletions src/components/Aggregator/hooks/useTokenApprove.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import { useAccount, useEstimateGas } from 'wagmi';
import { chainsMap, nativeAddress, tokenApprovalAbi } from '../constants';
import { useMutation, useQuery } from '@tanstack/react-query';
import { zeroAddress, erc20Abi, maxInt256, encodeFunctionData } from 'viem';
import { zeroAddress, maxInt256, encodeFunctionData } from 'viem';
import { arbitrum, fantom } from 'viem/chains';
import { readContract, waitForTransactionReceipt, writeContract } from 'wagmi/actions';
import { waitForTransactionReceipt, writeContract } from 'wagmi/actions';
import { config } from '~/components/WalletProvider';

// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
const oldErc = [
'0xdAC17F958D2ee523a2206206994597C13D831ec7'.toLowerCase(), // USDT
'0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32'.toLowerCase() // LDO
];
import { getAllowance, oldErc } from '../utils/getAllowance';

const chainsWithDefaultGasLimit = {
[fantom.id]: true,
Expand Down Expand Up @@ -59,35 +51,6 @@ const useApproveTokenSpend = () => {
return useMutation({ mutationFn: approveTokenSpend });
};

async function getAllowance({
token,
chain,
address,
spender
}: {
token?: string;
chain?: string;
address?: `0x${string}`;
spender?: `0x${string}`;
}) {
if (!spender || !token || !address || token === zeroAddress || !chain) {
return null;
}
try {
const allowance = await readContract(config, {
address: token as `0x${string}`,
abi: erc20Abi,
functionName: 'allowance',
args: [address, spender],
chainId: chainsMap[chain]
});

return allowance;
} catch (error) {
throw new Error(error instanceof Error ? `[Allowance]:${error.message}` : '[Allowance]: Failed to fetch allowance');
}
}

const useGetAllowance = ({
token,
spender,
Expand Down
Loading