-
Notifications
You must be signed in to change notification settings - Fork 222
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-Authored-By: Jayant Krishnamurthy <jayant@dourolabs.xyz>
- Loading branch information
1 parent
56beca0
commit 4e490b1
Showing
34 changed files
with
2,457 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
export declare const executeOpportunityAbi: { | ||
type: string; | ||
name: string; | ||
inputs: ({ | ||
name: string; | ||
type: string; | ||
internalType: string; | ||
components: { | ||
name: string; | ||
type: string; | ||
internalType: string; | ||
components: ({ | ||
name: string; | ||
type: string; | ||
internalType: string; | ||
components: { | ||
name: string; | ||
type: string; | ||
internalType: string; | ||
}[]; | ||
} | { | ||
name: string; | ||
type: string; | ||
internalType: string; | ||
components?: undefined; | ||
})[]; | ||
}[]; | ||
} | { | ||
name: string; | ||
type: string; | ||
internalType: string; | ||
components?: undefined; | ||
})[]; | ||
outputs: never[]; | ||
stateMutability: string; | ||
}; | ||
//# sourceMappingURL=abi.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.executeOpportunityAbi = void 0; | ||
exports.executeOpportunityAbi = { | ||
type: "function", | ||
name: "executeOpportunity", | ||
inputs: [ | ||
{ | ||
name: "params", | ||
type: "tuple", | ||
internalType: "struct ExecutionParams", | ||
components: [ | ||
{ | ||
name: "permit", | ||
type: "tuple", | ||
internalType: "struct ISignatureTransfer.PermitBatchTransferFrom", | ||
components: [ | ||
{ | ||
name: "permitted", | ||
type: "tuple[]", | ||
internalType: "struct ISignatureTransfer.TokenPermissions[]", | ||
components: [ | ||
{ | ||
name: "token", | ||
type: "address", | ||
internalType: "address", | ||
}, | ||
{ | ||
name: "amount", | ||
type: "uint256", | ||
internalType: "uint256", | ||
}, | ||
], | ||
}, | ||
{ | ||
name: "nonce", | ||
type: "uint256", | ||
internalType: "uint256", | ||
}, | ||
{ | ||
name: "deadline", | ||
type: "uint256", | ||
internalType: "uint256", | ||
}, | ||
], | ||
}, | ||
{ | ||
name: "witness", | ||
type: "tuple", | ||
internalType: "struct ExecutionWitness", | ||
components: [ | ||
{ | ||
name: "buyTokens", | ||
type: "tuple[]", | ||
internalType: "struct TokenAmount[]", | ||
components: [ | ||
{ | ||
name: "token", | ||
type: "address", | ||
internalType: "address", | ||
}, | ||
{ | ||
name: "amount", | ||
type: "uint256", | ||
internalType: "uint256", | ||
}, | ||
], | ||
}, | ||
{ | ||
name: "executor", | ||
type: "address", | ||
internalType: "address", | ||
}, | ||
{ | ||
name: "targetContract", | ||
type: "address", | ||
internalType: "address", | ||
}, | ||
{ | ||
name: "targetCalldata", | ||
type: "bytes", | ||
internalType: "bytes", | ||
}, | ||
{ | ||
name: "targetCallValue", | ||
type: "uint256", | ||
internalType: "uint256", | ||
}, | ||
{ | ||
name: "bidAmount", | ||
type: "uint256", | ||
internalType: "uint256", | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
name: "signature", | ||
type: "bytes", | ||
internalType: "bytes", | ||
}, | ||
], | ||
outputs: [], | ||
stateMutability: "payable", | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { OpportunityAdapterConfig, SvmConstantsConfig } from "./types"; | ||
export declare const OPPORTUNITY_ADAPTER_CONFIGS: Record<string, OpportunityAdapterConfig>; | ||
export declare const SVM_CONSTANTS: Record<string, SvmConstantsConfig>; | ||
//# sourceMappingURL=const.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SVM_CONSTANTS = exports.OPPORTUNITY_ADAPTER_CONFIGS = void 0; | ||
const web3_js_1 = require("@solana/web3.js"); | ||
exports.OPPORTUNITY_ADAPTER_CONFIGS = { | ||
op_sepolia: { | ||
chain_id: 11155420, | ||
opportunity_adapter_factory: "0xfA119693864b2F185742A409c66f04865c787754", | ||
opportunity_adapter_init_bytecode_hash: "0x3d71516d94b96a8fdca4e3a5825a6b41c9268a8e94610367e69a8462cc543533", | ||
permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3", | ||
weth: "0x74A4A85C611679B73F402B36c0F84A7D2CcdFDa3", | ||
}, | ||
mode: { | ||
chain_id: 34443, | ||
opportunity_adapter_factory: "0x59F78DE21a0b05d96Ae00c547BA951a3B905602f", | ||
opportunity_adapter_init_bytecode_hash: "0xd53b8e32ab2ecba07c3e3a17c3c5e492c62e2f7051b89e5154f52e6bfeb0e38f", | ||
permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3", | ||
weth: "0x4200000000000000000000000000000000000006", | ||
}, | ||
}; | ||
exports.SVM_CONSTANTS = { | ||
"development-solana": { | ||
expressRelayProgram: new web3_js_1.PublicKey("PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou"), | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { Bid, BidParams, OpportunityBid, OpportunityEvm } from "./types"; | ||
import { Hex } from "viem"; | ||
export declare function signBid(opportunity: OpportunityEvm, bidParams: BidParams, privateKey: Hex): Promise<Bid>; | ||
export declare function getSignature(opportunity: OpportunityEvm, bidParams: BidParams, privateKey: Hex): Promise<`0x${string}`>; | ||
export declare function signOpportunityBid(opportunity: OpportunityEvm, bidParams: BidParams, privateKey: Hex): Promise<OpportunityBid>; | ||
//# sourceMappingURL=evm.d.ts.map |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.signBid = signBid; | ||
exports.getSignature = getSignature; | ||
exports.signOpportunityBid = signOpportunityBid; | ||
const viem_1 = require("viem"); | ||
const accounts_1 = require("viem/accounts"); | ||
const index_1 = require("./index"); | ||
const const_1 = require("./const"); | ||
const abi_1 = require("./abi"); | ||
/** | ||
* Converts sellTokens, bidAmount, and callValue to permitted tokens | ||
* @param tokens List of sellTokens | ||
* @param bidAmount | ||
* @param callValue | ||
* @param weth | ||
* @returns List of permitted tokens | ||
*/ | ||
function getPermittedTokens(tokens, bidAmount, callValue, weth) { | ||
const permitted = tokens.map(({ token, amount }) => ({ | ||
token, | ||
amount, | ||
})); | ||
const wethIndex = permitted.findIndex(({ token }) => token === weth); | ||
const extraWethNeeded = bidAmount + callValue; | ||
if (wethIndex !== -1) { | ||
permitted[wethIndex].amount += extraWethNeeded; | ||
return permitted; | ||
} | ||
if (extraWethNeeded > 0) { | ||
permitted.push({ token: weth, amount: extraWethNeeded }); | ||
} | ||
return permitted; | ||
} | ||
function getOpportunityConfig(chainId) { | ||
const opportunityAdapterConfig = const_1.OPPORTUNITY_ADAPTER_CONFIGS[chainId]; | ||
if (!opportunityAdapterConfig) { | ||
throw new index_1.ClientError(`Opportunity adapter config not found for chain id: ${chainId}`); | ||
} | ||
return opportunityAdapterConfig; | ||
} | ||
async function signBid(opportunity, bidParams, privateKey) { | ||
const opportunityAdapterConfig = getOpportunityConfig(opportunity.chainId); | ||
const executor = (0, accounts_1.privateKeyToAccount)(privateKey).address; | ||
const permitted = getPermittedTokens(opportunity.sellTokens, bidParams.amount, opportunity.targetCallValue, (0, index_1.checkAddress)(opportunityAdapterConfig.weth)); | ||
const signature = await getSignature(opportunity, bidParams, privateKey); | ||
const calldata = makeAdapterCalldata(opportunity, permitted, executor, bidParams, signature); | ||
return { | ||
amount: bidParams.amount, | ||
targetCalldata: calldata, | ||
chainId: opportunity.chainId, | ||
targetContract: opportunityAdapterConfig.opportunity_adapter_factory, | ||
permissionKey: opportunity.permissionKey, | ||
env: "evm", | ||
}; | ||
} | ||
/** | ||
* Constructs the calldata for the opportunity adapter contract. | ||
* @param opportunity Opportunity to bid on | ||
* @param permitted Permitted tokens | ||
* @param executor Address of the searcher's wallet | ||
* @param bidParams Bid amount, nonce, and deadline timestamp | ||
* @param signature Searcher's signature for opportunity params and bidParams | ||
* @returns Calldata for the opportunity adapter contract | ||
*/ | ||
function makeAdapterCalldata(opportunity, permitted, executor, bidParams, signature) { | ||
return (0, viem_1.encodeFunctionData)({ | ||
abi: [abi_1.executeOpportunityAbi], | ||
args: [ | ||
[ | ||
[permitted, bidParams.nonce, bidParams.deadline], | ||
[ | ||
opportunity.buyTokens, | ||
executor, | ||
opportunity.targetContract, | ||
opportunity.targetCalldata, | ||
opportunity.targetCallValue, | ||
bidParams.amount, | ||
], | ||
], | ||
signature, | ||
], | ||
}); | ||
} | ||
async function getSignature(opportunity, bidParams, privateKey) { | ||
const types = { | ||
PermitBatchWitnessTransferFrom: [ | ||
{ name: "permitted", type: "TokenPermissions[]" }, | ||
{ name: "spender", type: "address" }, | ||
{ name: "nonce", type: "uint256" }, | ||
{ name: "deadline", type: "uint256" }, | ||
{ name: "witness", type: "OpportunityWitness" }, | ||
], | ||
OpportunityWitness: [ | ||
{ name: "buyTokens", type: "TokenAmount[]" }, | ||
{ name: "executor", type: "address" }, | ||
{ name: "targetContract", type: "address" }, | ||
{ name: "targetCalldata", type: "bytes" }, | ||
{ name: "targetCallValue", type: "uint256" }, | ||
{ name: "bidAmount", type: "uint256" }, | ||
], | ||
TokenAmount: [ | ||
{ name: "token", type: "address" }, | ||
{ name: "amount", type: "uint256" }, | ||
], | ||
TokenPermissions: [ | ||
{ name: "token", type: "address" }, | ||
{ name: "amount", type: "uint256" }, | ||
], | ||
}; | ||
const account = (0, accounts_1.privateKeyToAccount)(privateKey); | ||
const executor = account.address; | ||
const opportunityAdapterConfig = getOpportunityConfig(opportunity.chainId); | ||
const permitted = getPermittedTokens(opportunity.sellTokens, bidParams.amount, opportunity.targetCallValue, (0, index_1.checkAddress)(opportunityAdapterConfig.weth)); | ||
const create2Address = (0, viem_1.getContractAddress)({ | ||
bytecodeHash: opportunityAdapterConfig.opportunity_adapter_init_bytecode_hash, | ||
from: opportunityAdapterConfig.opportunity_adapter_factory, | ||
opcode: "CREATE2", | ||
salt: `0x${executor.replace("0x", "").padStart(64, "0")}`, | ||
}); | ||
return (0, accounts_1.signTypedData)({ | ||
privateKey, | ||
domain: { | ||
name: "Permit2", | ||
verifyingContract: (0, index_1.checkAddress)(opportunityAdapterConfig.permit2), | ||
chainId: opportunityAdapterConfig.chain_id, | ||
}, | ||
types, | ||
primaryType: "PermitBatchWitnessTransferFrom", | ||
message: { | ||
permitted, | ||
spender: create2Address, | ||
nonce: bidParams.nonce, | ||
deadline: bidParams.deadline, | ||
witness: { | ||
buyTokens: opportunity.buyTokens, | ||
executor, | ||
targetContract: opportunity.targetContract, | ||
targetCalldata: opportunity.targetCalldata, | ||
targetCallValue: opportunity.targetCallValue, | ||
bidAmount: bidParams.amount, | ||
}, | ||
}, | ||
}); | ||
} | ||
async function signOpportunityBid(opportunity, bidParams, privateKey) { | ||
const account = (0, accounts_1.privateKeyToAccount)(privateKey); | ||
const signature = await getSignature(opportunity, bidParams, privateKey); | ||
return { | ||
permissionKey: opportunity.permissionKey, | ||
bid: bidParams, | ||
executor: account.address, | ||
signature, | ||
opportunityId: opportunity.opportunityId, | ||
}; | ||
} |
Oops, something went wrong.