0xSpaceShard / starknet-hardhat-plugin

A plugin for integrating Starknet tools into Hardhat projects
https://0xspaceshard.github.io/starknet-hardhat-plugin/
MIT License
198 stars 36 forks source link

Support custom Accounts #148

Open ivpavici opened 2 years ago

ivpavici commented 2 years ago

Currently only OpenZeppelin and ArgentX are supported: as discussed here with Lauri: https://discord.com/channels/793094838509764618/961564209387282453 and here: https://discord.com/channels/793094838509764618/965952148418490418

FabijanC commented 1 year ago

Relevant: https://github.com/PhilippeR26/Account-Abstraction-for-Starknet-Hardhat

FabijanC commented 1 year ago

Maybe we can simply expose our existing Account abstract class (with potential modifications to make it more user-firendly). So far we didn't know how to expose classes in hre (so we did everything via functions, e.g. providing getContractFactory instead of exposing the StarknetContractFactory class with its constructor). It can probably be done as with Web3 in this example.

FabijanC commented 1 year ago

So, this happens to work, some things could be improved from the UX side, but if you are in need, by extending the Account abstract class you can instantiate custom objects with deploy and invoke functionalities.

import { Account } from "@shardlabs/starknet-hardhat-plugin/dist/src/account";
import { TransactionHashPrefix, StarknetChainId } from "@shardlabs/starknet-hardhat-plugin/dist/src/constants";

class MyAccount extends Account {
    // alternatively replace the constructor with a static initialize method if you need async code
    public constructor(...) {
        super(...);
    }

    protected getMessageHash(
        transactionHashPrefix: TransactionHashPrefix,
        accountAddress: string,
        callArray: Call[],
        nonce: string,
        maxFee: string,
        version: string,
        chainId: StarknetChainId
    ): string {
        throw new Error("Method not implemented.");
    }
    protected getSignatures(messageHash: string): bigint[] {
        throw new Error("Method not implemented.");
    }
    deployAccount(options?: DeployAccountOptions | undefined): Promise<string> {
        throw new Error("Method not implemented.");
    }
}

Usage example:

const myAccount = new MyAccount(...);
// fund the account before deploying it
// ...
await myAccount.deployAccount();

// declare and deploy
const contractFactory = starknet.getContractFactory(...);
await myAccount.declare(contractFactory);
const contract = await myAccount.deploy(contractFactory);

await myAccount.invoke(contract, ...);

For more info see how OpenZeppelinAccount is implemented (link).

FabijanC commented 1 year ago

As discussed with a user (Phil26 on Discord), the approach suggested in the previous post has bad UX.

Here is what exactly Phil said in the Discord thread:

Hello, I made some tests with this concept of support of account abstraction. It works, but to have all the inputs necessary to perform a new MyAccount() is too complicated ; the UX is really problematic. The best way is to have something similar to OZaccounts and ArgentXaccount : a protected constructor, and a static createAccount method. The dev has 2 steps : const myAccount=await MyAccount.createAccount(...), followed by myAccount.deployAccount(). I have also created 2 static methods, for standard signatures and hash : standardGetMessageHash() and standardGetSignatures(). By this way, a dev who is not working to customize these 2 points, has just to call these standard methods. They should be located in abstract Account class.

https://github.com/PhilippeR26/Account-Abstraction-for-Starknet-Hardhat/tree/main/scripts AAaccount.ts for the account definition testMyAA.ts for use example

irisdv commented 1 year ago

Can work on this one