Skip to content
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

Fix sender on EVM instance construction #12

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions examples/opensea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ const run = async (slug: string): Promise<void> => {
// 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
Expand Down
3 changes: 2 additions & 1 deletion examples/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ dotenv.config();
export async function setupNearEthConnection(): Promise<EVM> {
// 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!,
mpcContract: new MultichainContract(
account,
process.env.NEAR_MULTICHAIN_CONTRACT!
),
derivationPath: "ethereum,1",
});
}
3 changes: 1 addition & 2 deletions examples/transfer-1155.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ const run = async (): Promise<void> => {
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({
Expand Down
3 changes: 1 addition & 2 deletions examples/transfer-nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { setupNearEthConnection } from "./setup";

const run = async (): Promise<void> => {
const evm = await setupNearEthConnection();
const sender = await evm.getSender();
const amount = 0;
// TODO retrieve from user:
const tokenAddress = "0xb5EF4EbB25fCA7603C028610ddc9233d399dA34d";
Expand All @@ -14,7 +13,7 @@ const run = async (): Promise<void> => {
const callData = encodeFunctionData({
abi: erc721ABI,
functionName: "safeTransferFrom(address,address,uint256)",
args: [sender, to, tokenId],
args: [evm.sender, to, tokenId],
});

await evm.signAndSendTransaction({
Expand Down
55 changes: 33 additions & 22 deletions src/chains/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<Address> {
static async fromConfig(config: {
providerUrl: string;
scanUrl: string;
gasStationUrl: string;
mpcContract: MultichainContract;
derivationPath?: string;
}): Promise<EVM> {
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<void> => {
// 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<void> => {
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);
Expand All @@ -93,14 +103,15 @@ export class EVM {
}

private async buildTransaction(
tx: BaseTx,
sender: Address
tx: BaseTx
): Promise<FeeMarketEIP1559Transaction> {
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",
Expand All @@ -117,8 +128,8 @@ export class EVM {
return FeeMarketEIP1559Transaction.fromTxData(transactionDataWithGasLimit);
}

async createTxPayload(tx: BaseTx, sender: Address): Promise<TxPayload> {
const transaction = await this.buildTransaction(tx, sender);
async createTxPayload(tx: BaseTx): Promise<TxPayload> {
const transaction = await this.buildTransaction(tx);
console.log("Built Transaction", JSON.stringify(transaction));
const payload = Array.from(
new Uint8Array(transaction.getHashedMessageToSign().slice().reverse())
Expand All @@ -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");
Expand Down