Advertisement
ethdevs

Patch Swap

Jun 15th, 2023 (edited)
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import fetch from "node-fetch";
  2. import { ERC20TokenContract, WETH9Contract, ContractWrappers } from '@0x/contract-wrappers';
  3. import { BigNumber } from '@0x/utils';
  4. import axios from 'axios';
  5. import Web3 from 'web3';
  6. import qs from 'qs';
  7. import { ethers } from 'ethers';
  8. import { findTokenBySymbolOrName } from './data_all_tokens.js';
  9. import pkg from '@0x/contract-addresses';
  10. import dotenv from 'dotenv';
  11. dotenv.config();
  12.  
  13. // import { PatchWallet } from "./PatchWallet.js";
  14.  
  15. // ** PATCH CLASS **
  16. export class PatchWallet {
  17.     constructor() {
  18.         this.API_BASE_URL = 'https://paymagicapi.com/v1/';
  19.     }
  20.  
  21.     async auth(clientId, clientSecret) {
  22.         const url = `${this.API_BASE_URL}auth`;
  23.         const response = await axios.post(url, {
  24.             client_id: clientId,
  25.             client_secret: clientSecret,
  26.         });
  27.         return response.data.access_token;
  28.     }
  29.  
  30.     async accounts(users, token) {
  31.         const url = `${this.API_BASE_URL}resolver`;
  32.         const userIds = users.map(user => `${user.provider}:${user.username}`).join(',');
  33.         const response = await axios.post(url, {
  34.             userIds
  35.         }, {
  36.             headers: {
  37.                 'Content-Type': 'text/plain',
  38.                 'Authorization': `Bearer ${token}`,
  39.             },
  40.         });
  41.         return response.data;
  42.     }
  43.  
  44.     async tx(tx, token) {
  45.         const url = `${this.API_BASE_URL}base/tx`;
  46.         try {
  47.             const response = await axios.post(url, {
  48.                 ...tx,
  49.                 chain: tx.chain,
  50.             }, {
  51.                 headers: {
  52.                     'Content-Type': 'text/plain',
  53.                     'Authorization': `Bearer ${token}`,
  54.                 },
  55.             });
  56.             return response.data;
  57.         } catch (error) {
  58.             console.log(error);
  59.         }
  60.  
  61.     }
  62.  
  63.     async buildTx({ userId, chain, to, value, data}) {
  64.         // if (!accessToken) {
  65.         //   accessToken = await patch.auth(clientId, clientSecret);
  66.         // }
  67.  
  68.         const txInput = {
  69.             userId,
  70.             chain,
  71.             to: [to],
  72.             value: [value],
  73.             data: [data]
  74.         };
  75.         return txInput
  76.  
  77.  
  78.     }
  79. }
  80. const patch = new PatchWallet();
  81. const clientId = process.env.PATCH_CLIENT_ID
  82. const clientSecret = process.env.PATCH_CLIENT_SECRET;
  83.  
  84.  
  85.  
  86. //* SWAP FILE *//
  87. const { ContractAddresses  } = pkg;
  88. //import WETH contract address
  89. // let wethAddress = '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1'
  90. // const uni_token_arbitrum = '0xFa7F8980b0f1E64A2062791cc3b0871572f1F7f0';
  91. // const usdc_token_arbitrum = '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8';
  92. // const myaddress = "0x5A68C82e4355968DB53177033ad3eDCfD62aCCcA";
  93.  
  94. // //DEFAULT
  95. // const default_params = {
  96. //   sellToken: usdc_token_arbitrum,
  97. //   buyToken: uni_token_arbitrum,
  98. //   sellAmount: '1000000',
  99. //   takerAddress: myaddress, //users wallet
  100. // };
  101.  
  102. //note: wei = smallest unit of currency (not just eth)
  103. export function amountToWei(amount, decimals) {
  104.   const wei = new BigNumber(amount).times(new BigNumber(10).pow(decimals));
  105.   return wei;
  106. }
  107.  
  108. let web3
  109. export function getProvider(chainId) {
  110.     chainId = chainId.toString();
  111.    
  112.     switch (chainId) {
  113.         case '1':
  114.             const rUrlE = process.env.RPC_URL_MAINNET
  115.             web3 = new Web3(rUrlE);
  116.             return new ethers.providers.JsonRpcProvider(rUrE)
  117.         case '42161':
  118.             const rUrlA = process.env.RPC_URL_ARB_MAIN
  119.             web3 = new Web3(rUrlA);
  120.             return new ethers.providers.JsonRpcProvider(rUrlA)
  121.         case '137':
  122.             const rUrlM = process.env.RPC_URL_MATIC
  123.             web3 = new Web3(rUrlM)
  124.             return new ethers.providers.JsonRpcProvider(rUrlM)
  125.     }
  126. }
  127. export function get0xUrl(chainId) {
  128.     chainId = chainId.toString();
  129.     switch (chainId) {
  130.         case '1':
  131.             return 'https://api.0x.org/'
  132.         case '42161':
  133.             return 'https://arbitrum.api.0x.org/'
  134.         case '137':
  135.             return 'https://polygon.api.0x.org/'
  136.     }
  137. }
  138. // export const swap = async (swapOptions = {}) => {
  139. export const swap = async (inputTokenSymbol, outputTokenSymbol, inputAmount, takerAddress="0x5A68C82e4355968DB53177033ad3eDCfD62aCCcA", chainId=42161) => {
  140.     // const { ethers } = require('ethers')
  141.     let accessToken = await patch.auth(clientId, clientSecret);
  142.     // Set up provider and signer
  143.     const provider = getProvider(chainId); // Replace with your Infura Project ID
  144.     // const signer = new ethers.Wallet(process.env.ACCOUNT_PKEY, provider); // Replace with your private key
  145.    
  146.     // Set up ContractWrappers instance
  147.     const contractWrappers = new ContractWrappers(provider, { chainId: chainId }); // for Ethereum mainnet, chainId is 1
  148.  
  149.     //IF ETH MUST WRAP TO WETH & CHANGE INPUTTOKENSYMBOL TO WETH
  150.     // if (inputTokenSymbol.toLowerCase() === 'eth') {
  151.     //     inputTokenSymbol = 'WETH'; // Change to WETH
  152.    
  153.     //     const wethDetails = findTokenBySymbolOrName('WETH', chainId); // WETH contract details
  154.     //     const wethAddress = wethDetails.contractAddress; // Extracting the address from the details
  155.        
  156.     //     const WETHContract = new ethers.Contract(wethAddress, contractWrappers.weth9.abi, provider);
  157.     //     const weiAmount = ethers.utils.parseEther(inputAmount);
  158.    
  159.     //     // Call the built-in 'populateTransaction' method
  160.     //     let transactionData = await WETHContract.populateTransaction.deposit({
  161.     //         value: weiAmount,
  162.     //         gasLimit: ethers.utils.hexlify(10000000), // Gas limit - different gas limit for each network?
  163.     //     });
  164.  
  165.     //     //need patch to sign
  166.    
  167.  
  168.     //     // transactionData = await WETHContract.populateTransaction.deposit({
  169.     //     //     value: weiAmount,
  170.     //     //     gasLimit: ethers.utils.hexlify(10000000), // Gas limit - different gas limit for each network?
  171.     //     // });
  172.     //     // const tx = await WETHContract.deposit({
  173.     //     //     value: weiAmount,
  174.     //     //     gasLimit: ethers.utils.hexlify(10000000), // Gas limit - different gas limit for each network?
  175.     //     // });
  176.     //     const receipt = await tx.wait();
  177.     //     console.log('deposited eth to weth')
  178.        
  179.     // }
  180.     let convertedOutputTokenSymbolFrom = false
  181.      if (outputTokenSymbol.toLowerCase() === 'eth') {
  182.         outputTokenSymbol = 'weth'
  183.         convertedOutputTokenSymbolFrom = 'eth'
  184.     }
  185.  
  186.       let inputToken = findTokenBySymbolOrName(inputTokenSymbol, chainId)
  187.       let outputToken = findTokenBySymbolOrName(outputTokenSymbol, chainId)
  188.      
  189.       let inputAmountWei = amountToWei(inputAmount, inputToken.decimals).toString()
  190.  
  191.      
  192.       let params = {}
  193.       params.sellToken = inputToken.contractAddress
  194.       params.buyToken = outputToken.contractAddress
  195.       params.sellAmount = inputAmountWei
  196.       params.takerAddress = takerAddress
  197.  
  198.  
  199. //  
  200.   if (!params) {
  201.     params = default_params
  202.   }
  203.  
  204.   // const {
  205.   //   sellToken = params.sellToken || usdc_token_arbitrum,
  206.   //   buyToken = params.buyToken || uni_token_arbitrum,
  207.   //   sellAmount = params.sellAmount || '1000000',
  208.   //   takerAddress = params.takerAddress || myaddress
  209.   // } = params;
  210.  
  211.   let paramsForQuery = Object.assign({}, params);
  212.   delete  paramsForQuery.takerAddress; // Remove the takerAddress property from the queryParams object
  213.  
  214.   // const ZERO_EX_ADDRESS = '0xdef1c0ded9bec7f1a1670819833240f027b25eff';
  215.   const swapUrl = `${get0xUrl(chainId)}swap/v1/quote?`
  216.   const queryParams = `${qs.stringify(paramsForQuery)}`
  217.   const headers = { '0x-api-key': 'ef1357cf-4031-4dcb-a985-a1856193cc18' }
  218.   const quoteResponse = await fetch( swapUrl+queryParams, { headers } )//DON"T INCLUDE ADDR FOR QUOTE //PARAMS reference: https://0x.org/docs/0x-swap-api/guides/swap-tokens-with-0x-swap-api
  219.   const quote = await quoteResponse.json();
  220.  
  221.  
  222.     const SellTokenContract = new ERC20TokenContract(params.sellToken, web3.eth.currentProvider);
  223.  
  224.     const currentAllowance = await SellTokenContract.allowance(params.takerAddress, quote.allowanceTarget).callAsync();
  225.     console.log(`Your allowance for the 0x Exchange Proxy is ${currentAllowance} tokens.`);
  226.     // const currentAllowance = new BigNumber(
  227.     //     USDCcontract.allowance(params.takerAddress, ZERO_EX_ADDRESS)
  228.     //     );
  229.     const big_currentAllowance = new BigNumber(currentAllowance);
  230.     const big_sellAmount = new BigNumber(params.sellAmount);
  231.  
  232.     console.log(big_currentAllowance.isLessThan(big_sellAmount));
  233.     const maxApproval = new BigNumber(2).pow(256).minus(1);
  234.  
  235.     let approvalTx = false
  236.         if (currentAllowance.isLessThan(params.sellAmount)) {
  237.             console.log("current allowance is less than sellAmount")
  238.             const approvalTxData = SellTokenContract.approve(quote.allowanceTarget, maxApproval).getABIEncodedTransactionData();
  239.             const nonce = await web3.eth.getTransactionCount(takerAddress);
  240.  
  241.             const txInput = {
  242.                 userId:  "lang:imran",
  243.                 chain: "matic",
  244.                 to: [`${outputToken.contractAddress}`],
  245.                 value: ["0"],
  246.                 data: [approvalTxData],
  247.             };
  248.            
  249.             const tx = await patch.tx(txInput, accessToken);
  250.             console.log('approval tx', tx)
  251.  
  252.         }
  253.         const baseFeePerGas = await provider.getGasPrice();
  254.  
  255.         const maxPriorityFeePerGas = ethers.utils.parseUnits('0.4', 'gwei');
  256.         const maxFeePerGas = baseFeePerGas.add(maxPriorityFeePerGas);
  257.  
  258.         const gweiToWei = (gweiValue) => {
  259.             return ethers.utils.parseUnits(gweiValue.toString(), "gwei");
  260.           };
  261.  
  262.         // let etherBalanceBefore = await provider.getBalance(takerAddress)
  263.         // etherBalanceBefore =  ethers.utils.formatEther(etherBalanceBefore);
  264.         // const nonce = await web3.eth.getTransactionCount(myaddress);
  265.  
  266.         // here we'd send back:
  267.         let tx_data = quote.data
  268.         let tx_to = quote.to
  269.         let tx_from = quote.from
  270.  
  271.         const swapInput = {
  272.             userId:  "lang:imran",
  273.             chain: "matic",
  274.             to: [`${quote.to}`], // USDC
  275.             value: [`${quote.value}`],
  276.             data: [`${quote.data}`], // Send 0.01 USDC to my account
  277.         };
  278.        
  279.  
  280.         accessToken = await patch.auth(clientId, clientSecret);
  281.         const tx = await patch.tx(swapInput, accessToken);
  282.  
  283.  
  284.  
  285.         try {
  286.           const tx =  await signer.sendTransaction({
  287.             from: quote.from,
  288.             to: quote.to,
  289.             data: quote.data,
  290.             value: ethers.BigNumber.from(quote.value || 0),
  291.             // gasPrice: quote.gas, //?? 1304845598380 // Set an appropriate gas limit for the transaction
  292.             gasLimit: quote.gas,
  293.             // nonce: nonce,
  294.             maxPriorityFeePerGas: ethers.utils.parseUnits('0.001', "gwei"),
  295.             maxFeePerGas: ethers.utils.parseUnits('0.15', "gwei"),
  296.  
  297.           });
  298.           const swapTx = tx
  299.  
  300.           return {
  301.             approvalTx: approvalTx,
  302.             swapTx: swapTx,
  303.             etherBalanceBefore: etherBalanceBefore,
  304.             etherBalanceAfter: etherBalanceAfter,
  305.             comment: unwrapComment
  306.           };
  307.      
  308.         } catch(err) {
  309.           console.log("swap error", err,  err.message)
  310.           return 'swap failed!'
  311.  
  312.         }
  313.  
  314.     }
  315.    
  316.     //this addr is the lang:imran acct
  317.     swap("USDC", "uni", "0.1", '0x4c8c013AC1d7406647d88A7f5620E737A92F726b', 137).then( (result) => {
  318.       console.log(result);
  319.     })
  320.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement