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

Add Near Adapter for Signature #1

Merged
merged 12 commits into from
Jun 14, 2024
Merged

Add Near Adapter for Signature #1

merged 12 commits into from
Jun 14, 2024

Conversation

bh2smith
Copy link
Collaborator

@bh2smith bh2smith commented Jun 11, 2024

This PR adds NearEthAdapter and Signature producing.

However, we hit a few hurdles

Encountered Issues & Resolutions

Solved (kinda): Conflicting Import Formats in Dependencies
➜  nearly-safe git:(near-adapter) yarn start
yarn run v1.22.22
$ ts-node index.ts
/Users/bh2smith/Projects/bh2smith/nearly-safe/node_modules/near-ca/dist/index.js:1
export * from "./chains/ethereum";
^^^^^^

SyntaxError: Unexpected token 'export'

Which may be due to the project's configuration for ESNext?

Resolution: made some weird/random changes to near-ca library BitteProtocol/near-ca#66

Solved: Invalid Request Payload for sendUserOp

We updated the dependency and got past the signature production. Now we seem to have a problem with required field and not allowed fields on our transaction encoding parameters.

Error: "params[0].factory" is not allowed. Error: entryPointAddress is required. "params[0].sender" is not allowed

So I was looking at biconomy docs for the expected parameter formats and see some subtle differences:

https://docs.biconomy.io/Bundler/api/send-UserOperation

Our Params:
https://jsonblob.com/1250364234331447296
Theirs:
https://docs.biconomy.io/Bundler/api/send-UserOperation#request

I am gonna try and figure out the correct request payload and write some transformer for it.

Resolution: Wrote some type interfaces and a transformer method. Essentially just
(factory, factoryData) => initCode: concat(factory, factoryData)

Solved: Entry Point Not Supported.

I tried two different bundlers, both resulted in various different "Entry Point Not Supported" errors

Biconomy:

Error: {"code":400,"message":"Entry point not supported by Bundler"}

Public URL (https://docs.stackup.sh/docs/public-bundler-rpc)
https://public.stackup.sh/api/v1/node/ethereum-sepolia

Error: {"code":-32601,"data":"entryPoint: Implementation not supported","message":"entryPoint: Implementation not supported"}

Resolution: The following curl request returns the bundler's preferred entrypoint

curl -X POST $BUNDLER_URL -H "Content-Type: application/json" \
     -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "eth_supportedEntryPoints",
       "params": []
     }'
Solved: Reverted or Out of Gas [Likely Reverted]

We had initially hard-coded some pretty high gas limits (100k without initialization and 500k with). Still getting the following response:

Error: {"code":-32500,"data":"AA23 reverted (or OOG)","message":"AA23 reverted (or OOG)"}

We attempted to bump the hard coded limits to 200k & 1M before assuming the transaction reverts, but still got the same error.

Thus we assume that the transaction is reverting 😢

On Tenderly: simulateHandleOp: transaction is reverting with "AA20 account not deployed"

When calling simulatHandleOp directly we get "AA23 OOG"

Resolution: This was an issue with EntryPoint Contract version compatibilty. Biconomy and the public endpoints are using a (possibly older) version that supports PackedUserOperation while Pimlico uses version 0.7 that supports the UserOperation type.

Solved: AA24 signature error

We are getting the signature from near-ca library which produces ECDA signatures for hashes. In our case we are requesting a signature for this safeOpHash

const hash = safeOpHash;
const viemHash = typeof hash === "string" ? (hash as `0x${string}`) : hash;
// MPC Contract produces two possible signatures.
const signatures = await adapter.sign(viemHash);

Could it be that there is something different that needs to be signed? or that the means of recovery is different? Like with signMessage, signTypedData, signTx?

Resolution: Signature bytes were incorrect - 0b7b8c7

Solved: Safe Address retrieval after deployment Safe already exists for nonce > 0. Need to determine safe address when its already been deployed! So, this
await contracts.proxyFactory.createProxyWithNonce.staticCall(
      contracts.singleton,
      setup,
      SAFE_SALT_NONCE,
    );

wouldn't work for address retrieval. Instead we use ethers.getCreate2Address: 07975d6

Unresolved/Open Issues (For Future PRs)

  1. UserOpHash is returned from sendUserOp, not the TxHash. There are endpoints to get the a receipt (containing the txHash), but they are not immediately available... should we sleep or continue requesting until its available? Retrieve TxHash From UserOpHash #2
  2. Gas Fee Fetching is naive (bundler suggests using theirs). Use Bundler Gas Data Feed #3
  3. Use Paymaster Service. Integrate Paymaster Service #4
  4. Bonus: AddOwnerWithThreadhold (as recovery mechanism)

@bh2smith bh2smith requested a review from nlordell June 11, 2024 21:01
package.json Show resolved Hide resolved
index.ts Outdated Show resolved Hide resolved
index.ts Outdated Show resolved Hide resolved
index.ts Outdated Show resolved Hide resolved
index.ts Outdated Show resolved Hide resolved
index.ts Outdated Show resolved Hide resolved
package.json Show resolved Hide resolved
index.ts Outdated Show resolved Hide resolved
Co-authored-by: Nicholas Rodrigues Lordello <[email protected]>
index.ts Outdated Show resolved Hide resolved
.env.sample Outdated Show resolved Hide resolved
@bh2smith
Copy link
Collaborator Author

bh2smith commented Jun 14, 2024

We have our first transaction!

https://sepolia.etherscan.io/tx/0xb9813a1a43d9b3caa94d33a5c504d224d571ed9c6217f88f99f85a5d2cdffb7c

Unfortunately, now that the account has been deployed I can't run it again. We are failing at static call to create proxy with nonce. The revert message doesn't seem to contain the address so I am battling with trying to pass in the correct parameters to

ethers.getCreate2Address(
   factoryAddress,  // await contracts.proxyFactory.getAddress(),
   saltHex, // ethers.keccak256(SAFE_SALT_NONCE!),
   initCodeHash,  // ethers.keccak256(setup)
)

At least one of those three things I've tried is wrong...

I think maybe hashing the setup is incorrect because the initCode is actually a subset of all the setup data.... Maybe?

I am trying to look through the transaction of deployment to read the values that were used and I can not tell what to put into this!

https://dashboard.tenderly.co/tx/sepolia/0xb9813a1a43d9b3caa94d33a5c504d224d571ed9c6217f88f99f85a5d2cdffb7c/debugger?trace=0.1.1.0.0

@bh2smith
Copy link
Collaborator Author

I also tried to add another owner (keeping the threshold the same) and it failed:
Transaction: 0x344ab829aa6b9a6ca765d05d5b2cf0600b4e73066f92d242cb3e6c3d52d11aa3

with revert Reason: ACFDB444

@nlordell
Copy link
Collaborator

I also tried to add another owner (keeping the threshold the same) and it failed:
Transaction: 0x344ab829aa6b9a6ca765d05d5b2cf0600b4e73066f92d242cb3e6c3d52d11aa3

checkSignatures is reverting. Also, it looks like you are doing calling execTransaction on the Safe? That doesn't make sense to me. You should instead call addOwnerWithThreshold on the Safe directly.

@nlordell
Copy link
Collaborator

nlordell commented Jun 14, 2024

Unfortunately, now that the account has been deployed I can't run it again. We are failing at static call to create proxy with nonce. The revert message doesn't seem to contain the address so I am battling with trying to pass in the correct parameters to

You should look at the code of the factory:

  • salt is a combination of the setup calldata and the saltNonce (should be clear from the proxy factory code)
  • initCode is the proxy initialization code. There should be a proxyCode() or similarly named method on the proxy factory contract that you can call.

@bh2smith
Copy link
Collaborator Author

bh2smith commented Jun 14, 2024

@nlordell can you please help me figure out what I am doing wrong here?

    // based on: bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
    const salt = ethers.keccak256(
      ethers.solidityPacked(["bytes32", "uint256"], 
        [ethers.keccak256(setup), SAFE_SALT_NONCE!]), 
    );
    const initCode = await contracts.proxyFactory.proxyCreationCode();
    const x = ethers.getCreate2Address(
      await contracts.proxyFactory.getAddress(),
      salt,
      ethers.keccak256(initCode)
    )

@nlordell
Copy link
Collaborator

@bh2smith
Copy link
Collaborator Author

bh2smith commented Jun 14, 2024

Awesome! I got it now! I think maybe this PR has become poultry and is in good enough state to merge. I would like to continue by cleaning it up, separating the functionality into different files, getting the types right and stuff like that. Cool with you @nlordell? Or is there something else you like to see here before that?

Note that the bundler service is now telling us our gas fees are too low and suggesting we use their endpoint.

Comment on lines -108 to -112
await contracts.proxyFactory.createProxyWithNonce.staticCall(
contracts.singleton,
setup,
SAFE_SALT_NONCE,
);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was removed in favour of getCreate2Address (which should work in all cases - instead of only pre-deployment).

@bh2smith
Copy link
Collaborator Author

Merging cuz I wanna continue on all the other stuffs.

@bh2smith bh2smith merged commit 278762c into main Jun 14, 2024
@bh2smith bh2smith deleted the near-adapter branch June 14, 2024 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants