evm.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.signBid = signBid;
  4. exports.getSignature = getSignature;
  5. exports.signOpportunityBid = signOpportunityBid;
  6. const viem_1 = require("viem");
  7. const accounts_1 = require("viem/accounts");
  8. const index_1 = require("./index");
  9. const const_1 = require("./const");
  10. const abi_1 = require("./abi");
  11. /**
  12. * Converts sellTokens, bidAmount, and callValue to permitted tokens
  13. * @param tokens List of sellTokens
  14. * @param bidAmount
  15. * @param callValue
  16. * @param weth
  17. * @returns List of permitted tokens
  18. */
  19. function getPermittedTokens(tokens, bidAmount, callValue, weth) {
  20. const permitted = tokens.map(({ token, amount }) => ({
  21. token,
  22. amount,
  23. }));
  24. const wethIndex = permitted.findIndex(({ token }) => token === weth);
  25. const extraWethNeeded = bidAmount + callValue;
  26. if (wethIndex !== -1) {
  27. permitted[wethIndex].amount += extraWethNeeded;
  28. return permitted;
  29. }
  30. if (extraWethNeeded > 0) {
  31. permitted.push({ token: weth, amount: extraWethNeeded });
  32. }
  33. return permitted;
  34. }
  35. function getOpportunityConfig(chainId) {
  36. const opportunityAdapterConfig = const_1.OPPORTUNITY_ADAPTER_CONFIGS[chainId];
  37. if (!opportunityAdapterConfig) {
  38. throw new index_1.ClientError(`Opportunity adapter config not found for chain id: ${chainId}`);
  39. }
  40. return opportunityAdapterConfig;
  41. }
  42. async function signBid(opportunity, bidParams, privateKey) {
  43. const opportunityAdapterConfig = getOpportunityConfig(opportunity.chainId);
  44. const executor = (0, accounts_1.privateKeyToAccount)(privateKey).address;
  45. const permitted = getPermittedTokens(opportunity.sellTokens, bidParams.amount, opportunity.targetCallValue, (0, index_1.checkAddress)(opportunityAdapterConfig.weth));
  46. const signature = await getSignature(opportunity, bidParams, privateKey);
  47. const calldata = makeAdapterCalldata(opportunity, permitted, executor, bidParams, signature);
  48. return {
  49. amount: bidParams.amount,
  50. targetCalldata: calldata,
  51. chainId: opportunity.chainId,
  52. targetContract: opportunityAdapterConfig.opportunity_adapter_factory,
  53. permissionKey: opportunity.permissionKey,
  54. env: "evm",
  55. };
  56. }
  57. /**
  58. * Constructs the calldata for the opportunity adapter contract.
  59. * @param opportunity Opportunity to bid on
  60. * @param permitted Permitted tokens
  61. * @param executor Address of the searcher's wallet
  62. * @param bidParams Bid amount, nonce, and deadline timestamp
  63. * @param signature Searcher's signature for opportunity params and bidParams
  64. * @returns Calldata for the opportunity adapter contract
  65. */
  66. function makeAdapterCalldata(opportunity, permitted, executor, bidParams, signature) {
  67. return (0, viem_1.encodeFunctionData)({
  68. abi: [abi_1.executeOpportunityAbi],
  69. args: [
  70. [
  71. [permitted, bidParams.nonce, bidParams.deadline],
  72. [
  73. opportunity.buyTokens,
  74. executor,
  75. opportunity.targetContract,
  76. opportunity.targetCalldata,
  77. opportunity.targetCallValue,
  78. bidParams.amount,
  79. ],
  80. ],
  81. signature,
  82. ],
  83. });
  84. }
  85. async function getSignature(opportunity, bidParams, privateKey) {
  86. const types = {
  87. PermitBatchWitnessTransferFrom: [
  88. { name: "permitted", type: "TokenPermissions[]" },
  89. { name: "spender", type: "address" },
  90. { name: "nonce", type: "uint256" },
  91. { name: "deadline", type: "uint256" },
  92. { name: "witness", type: "OpportunityWitness" },
  93. ],
  94. OpportunityWitness: [
  95. { name: "buyTokens", type: "TokenAmount[]" },
  96. { name: "executor", type: "address" },
  97. { name: "targetContract", type: "address" },
  98. { name: "targetCalldata", type: "bytes" },
  99. { name: "targetCallValue", type: "uint256" },
  100. { name: "bidAmount", type: "uint256" },
  101. ],
  102. TokenAmount: [
  103. { name: "token", type: "address" },
  104. { name: "amount", type: "uint256" },
  105. ],
  106. TokenPermissions: [
  107. { name: "token", type: "address" },
  108. { name: "amount", type: "uint256" },
  109. ],
  110. };
  111. const account = (0, accounts_1.privateKeyToAccount)(privateKey);
  112. const executor = account.address;
  113. const opportunityAdapterConfig = getOpportunityConfig(opportunity.chainId);
  114. const permitted = getPermittedTokens(opportunity.sellTokens, bidParams.amount, opportunity.targetCallValue, (0, index_1.checkAddress)(opportunityAdapterConfig.weth));
  115. const create2Address = (0, viem_1.getContractAddress)({
  116. bytecodeHash: opportunityAdapterConfig.opportunity_adapter_init_bytecode_hash,
  117. from: opportunityAdapterConfig.opportunity_adapter_factory,
  118. opcode: "CREATE2",
  119. salt: `0x${executor.replace("0x", "").padStart(64, "0")}`,
  120. });
  121. return (0, accounts_1.signTypedData)({
  122. privateKey,
  123. domain: {
  124. name: "Permit2",
  125. verifyingContract: (0, index_1.checkAddress)(opportunityAdapterConfig.permit2),
  126. chainId: opportunityAdapterConfig.chain_id,
  127. },
  128. types,
  129. primaryType: "PermitBatchWitnessTransferFrom",
  130. message: {
  131. permitted,
  132. spender: create2Address,
  133. nonce: bidParams.nonce,
  134. deadline: bidParams.deadline,
  135. witness: {
  136. buyTokens: opportunity.buyTokens,
  137. executor,
  138. targetContract: opportunity.targetContract,
  139. targetCalldata: opportunity.targetCalldata,
  140. targetCallValue: opportunity.targetCallValue,
  141. bidAmount: bidParams.amount,
  142. },
  143. },
  144. });
  145. }
  146. async function signOpportunityBid(opportunity, bidParams, privateKey) {
  147. const account = (0, accounts_1.privateKeyToAccount)(privateKey);
  148. const signature = await getSignature(opportunity, bidParams, privateKey);
  149. return {
  150. permissionKey: opportunity.permissionKey,
  151. bid: bidParams,
  152. executor: account.address,
  153. signature,
  154. opportunityId: opportunity.opportunityId,
  155. };
  156. }