Skip to content

Commit

Permalink
fix: support contract deployment by a smart contract account
Browse files Browse the repository at this point in the history
  • Loading branch information
moldy530 committed Jun 20, 2023
1 parent bb24e2d commit 1cb8fb7
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 16 deletions.
10 changes: 10 additions & 0 deletions packages/core/src/__tests__/simple-account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,14 @@ describe("Simple Account Tests", () => {
'"0x18dfb3c7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"'
);
});

it("should successfully deploy a contract", async () => {
const result = signer.deployContract({
abi: [],
bytecode:
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e5284ae00a989ec593ad1aebb69c9082d4820ccd98f6b493e4c442fa44a950c364736f6c63430008110033",
});

await expect(result).resolves.not.toThrowError();
});
});
3 changes: 2 additions & 1 deletion packages/core/src/account/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
concatHex,
encodeFunctionData,
hexToBytes,
zeroAddress,
type FallbackTransport,
type Hex,
type Transport,
Expand Down Expand Up @@ -64,7 +65,7 @@ export class SimpleSmartContractAccount<
): Promise<`0x${string}`> {
const [targets, datas] = _txs.reduce(
(accum, curr) => {
accum[0].push(curr.target);
accum[0].push(curr.target ?? zeroAddress);
accum[1].push(curr.data);

return accum;
Expand Down
39 changes: 27 additions & 12 deletions packages/core/src/provider/base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {
encodeDeployData,
fromHex,
zeroAddress,
type Address,
type Chain,
type EncodeDeployDataParameters,
type Hash,
type RpcTransactionRequest,
type Transport,
Expand Down Expand Up @@ -141,10 +144,6 @@ export class SmartAccountProvider<
};

sendTransaction = async (request: RpcTransactionRequest): Promise<Hash> => {
if (!request.to) {
throw new Error("transaction is missing to address");
}

// TODO: need to add support for overriding gas prices
const { hash } = await this.sendUserOperation({
target: request.to,
Expand All @@ -157,12 +156,6 @@ export class SmartAccountProvider<

sendTransactions = async (requests: RpcTransactionRequest[]) => {
const batch = requests.map((request) => {
if (!request.to) {
throw new Error(
"one transaction in the batch is missing a target address"
);
}

// TODO: need to add support for overriding gas prices
return {
target: request.to,
Expand Down Expand Up @@ -222,8 +215,18 @@ export class SmartAccountProvider<
sender: this.getAddress(),
nonce: this.account.getNonce(),
callData: Array.isArray(data)
? this.account.encodeBatchExecute(data)
: this.account.encodeExecute(data.target, data.value ?? 0n, data.data),
? this.account.encodeBatchExecute(
data.map((x) => ({
...x,
target: x.target ?? zeroAddress,
value: x.value ?? 0n,
}))
)
: this.account.encodeExecute(
data.target ?? zeroAddress,
data.value ?? 0n,
data.data
),
signature: this.account.getDummySignature(),
} as UserOperationStruct);

Expand Down Expand Up @@ -256,6 +259,18 @@ export class SmartAccountProvider<
};
};

deployContract = async (
params: EncodeDeployDataParameters
): Promise<Hash> => {
const deployData = encodeDeployData(params);
const { hash } = await this.sendUserOperation({
target: zeroAddress,
data: deployData,
});

return hash;
};

// These are dependent on the specific paymaster being used
// You should implement your own middleware to override these
// or extend this class and provider your own implemenation
Expand Down
17 changes: 15 additions & 2 deletions packages/core/src/provider/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { Address } from "abitype";
import type { Hash, RpcTransactionRequest, Transport } from "viem";
import type {
EncodeDeployDataParameters,
Hash,
RpcTransactionRequest,
Transport,
} from "viem";
import type { BaseSmartContractAccount } from "../account/base.js";
import type {
PublicErc4337Client,
Expand All @@ -18,7 +23,7 @@ type WithRequired<T, K extends keyof T> = Required<Pick<T, K>>;
type WithOptional<T, K extends keyof T> = Pick<Partial<T>, K>;

export type SendUserOperationResult = {
hash: string;
hash: Hash;
request: UserOperationRequest;
};

Expand Down Expand Up @@ -128,6 +133,14 @@ export interface ISmartAccountProvider<
*/
sendTransactions: (request: RpcTransactionRequest[]) => Promise<Hash>;

/**
* This takes contract deploy parameters and crafts a UserOperation to deploy the contract.
*
* @param params the parameters for the contract deploy call
* @returns the hash of the user operation
*/
deployContract: (params: EncodeDeployDataParameters) => Promise<Hash>;

/**
* EIP-1193 compliant request method
*
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type BytesLike = Uint8Array | string;

export interface UserOperationCallData {
/* the target of the call */
target: Address;
target?: Address;
/* the data passed to the target */
data: Hex;
/* the amount of native token to send to the target (default: 0) */
Expand Down
17 changes: 17 additions & 0 deletions packages/ethers/src/__tests__/simple-account.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getChain, SimpleSmartContractAccount } from "@alchemy/aa-core";
import { Interface } from "@ethersproject/abi";
import { ContractFactory } from "@ethersproject/contracts";
import { Wallet } from "@ethersproject/wallet";
import { Alchemy, Network } from "alchemy-sdk";
import { EthersProviderAdapter } from "../provider-adapter.js";
Expand Down Expand Up @@ -80,4 +82,19 @@ describe("Simple Account Tests", async () => {

await expect(result).rejects.toThrowError();
});

it("should successfully deploy a contract", async () => {
const factory = new ContractFactory(
new Interface([]),
{
object:
"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e5284ae00a989ec593ad1aebb69c9082d4820ccd98f6b493e4c442fa44a950c364736f6c63430008110033",
},
signer
);

const result = factory.deploy();

await expect(result).resolves.not.toThrowError();
});
});

0 comments on commit 1cb8fb7

Please sign in to comment.