diff --git a/examples/opensea.ts b/examples/opensea.ts index 57ea834..f7d737f 100644 --- a/examples/opensea.ts +++ b/examples/opensea.ts @@ -43,9 +43,8 @@ const run = async (slug: string): Promise => { // This sleep is due to free-tier testnet rate limiting. await sleep(1000); const evm = await setupNearEthConnection(); - const sender = await evm.getSender(); const data = await openseaSDK.api.generateFulfillmentData( - sender, + evm.sender, cheapestAvailable.order_hash, cheapestAvailable.protocol_address, OrderSide.ASK diff --git a/examples/setup.ts b/examples/setup.ts index 76980b5..e6d3da7 100644 --- a/examples/setup.ts +++ b/examples/setup.ts @@ -7,7 +7,7 @@ dotenv.config(); export async function setupNearEthConnection(): Promise { // This also reads from process.env! const account = await getNearAccount(); - return new EVM({ + return EVM.fromConfig({ providerUrl: process.env.NODE_URL!, scanUrl: process.env.SCAN_URL!, gasStationUrl: process.env.GAS_STATION_URL!, @@ -15,5 +15,6 @@ export async function setupNearEthConnection(): Promise { account, process.env.NEAR_MULTICHAIN_CONTRACT! ), + derivationPath: "ethereum,1", }); } diff --git a/examples/transfer-1155.ts b/examples/transfer-1155.ts index 720b0a1..2fa3bcd 100644 --- a/examples/transfer-1155.ts +++ b/examples/transfer-1155.ts @@ -9,12 +9,11 @@ const run = async (): Promise => { const tokenAddress = "0x284c37b0fcb72034ff25855da57fcf097b255474"; const tokenId = 1; const to = "0x8d99F8b2710e6A3B94d9bf465A98E5273069aCBd"; - const from = await evm.getSender(); const callData = encodeFunctionData({ abi: erc1155Abi, functionName: "safeTransferFrom(address,address,uint256,uint256,bytes)", - args: [from, to, tokenId, 1, "0x"], + args: [evm.sender, to, tokenId, 1, "0x"], }); await evm.signAndSendTransaction({ diff --git a/examples/transfer-nft.ts b/examples/transfer-nft.ts index e3bbee6..007e353 100644 --- a/examples/transfer-nft.ts +++ b/examples/transfer-nft.ts @@ -4,7 +4,6 @@ import { setupNearEthConnection } from "./setup"; const run = async (): Promise => { const evm = await setupNearEthConnection(); - const sender = await evm.getSender(); const amount = 0; // TODO retrieve from user: const tokenAddress = "0xb5EF4EbB25fCA7603C028610ddc9233d399dA34d"; @@ -14,7 +13,7 @@ const run = async (): Promise => { const callData = encodeFunctionData({ abi: erc721ABI, functionName: "safeTransferFrom(address,address,uint256)", - args: [sender, to, tokenId], + args: [evm.sender, to, tokenId], }); await evm.signAndSendTransaction({ diff --git a/src/chains/ethereum.ts b/src/chains/ethereum.ts index 49fe8ed..55c0352 100644 --- a/src/chains/ethereum.ts +++ b/src/chains/ethereum.ts @@ -23,6 +23,8 @@ export class EVM { private scanUrl: string; private gasStationUrl: string; private mpcContract: MultichainContract; + private derivationPath: string; + sender: Address; /** * Constructs an EVM instance with the provided configuration. @@ -38,40 +40,48 @@ export class EVM { scanUrl: string; gasStationUrl: string; mpcContract: MultichainContract; + derivationPath: string; + sender: Address; }) { this.client = createPublicClient({ transport: http(config.providerUrl) }); this.scanUrl = config.scanUrl; this.mpcContract = config.mpcContract; this.gasStationUrl = config.gasStationUrl; + this.derivationPath = config.derivationPath; + this.sender = config.sender; } - getSender(derivationPath?: string): Promise
{ + static async fromConfig(config: { + providerUrl: string; + scanUrl: string; + gasStationUrl: string; + mpcContract: MultichainContract; + derivationPath?: string; + }): Promise { + const { derivationPath, ...rest } = config; + // Sender is uniquely determined by the derivation path! const path = derivationPath || "ethereum,1"; - return this.mpcContract.deriveEthAddress(path); + return new EVM({ + sender: await config.mpcContract.deriveEthAddress(path), + derivationPath: path, + ...rest, + }); } - signAndSendTransaction = async ( - txData: BaseTx, - options?: { - derivationPath: string; - } - ): Promise => { - // Sender is uniquely determined by the derivation path! - const path = options?.derivationPath || "ethereum,1"; - const sender = await this.getSender(path); - console.log("Creating Payload for sender:", sender); - const { transaction, payload } = await this.createTxPayload(txData, sender); + signAndSendTransaction = async (txData: BaseTx): Promise => { + console.log("Creating Payload for sender:", this.sender); + const { transaction, payload } = await this.createTxPayload(txData); console.log("Requesting signature from Near..."); const { big_r, big_s } = await this.mpcContract.requestSignature( payload, - path + this.derivationPath ); const signedTx = EVM.reconstructSignature( transaction, big_r, big_s, - sender + this.sender ); console.log("Relaying signed tx to EVM..."); await this.relayTransaction(signedTx); @@ -93,14 +103,15 @@ export class EVM { } private async buildTransaction( - tx: BaseTx, - sender: Address + tx: BaseTx ): Promise { - const nonce = await this.client.getTransactionCount({ address: sender }); + const nonce = await this.client.getTransactionCount({ + address: this.sender, + }); const { maxFeePerGas, maxPriorityFeePerGas } = await this.queryGasPrice(); const transactionData = { nonce, - account: sender, + account: this.sender, to: tx.receiver, value: parseEther(tx.amount.toString()), data: tx.data || "0x", @@ -117,8 +128,8 @@ export class EVM { return FeeMarketEIP1559Transaction.fromTxData(transactionDataWithGasLimit); } - async createTxPayload(tx: BaseTx, sender: Address): Promise { - const transaction = await this.buildTransaction(tx, sender); + async createTxPayload(tx: BaseTx): Promise { + const transaction = await this.buildTransaction(tx); console.log("Built Transaction", JSON.stringify(transaction)); const payload = Array.from( new Uint8Array(transaction.getHashedMessageToSign().slice().reverse()) @@ -130,7 +141,7 @@ export class EVM { transaction: FeeMarketEIP1559Transaction, big_r: string, big_s: string, - sender: string + sender: Address ): FeeMarketEIP1559Transaction => { const r = Buffer.from(big_r.substring(2), "hex"); const s = Buffer.from(big_s, "hex");