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

Starknet support #3

Open
adambor opened this issue Dec 14, 2024 · 8 comments
Open

Starknet support #3

adambor opened this issue Dec 14, 2024 · 8 comments

Comments

@adambor
Copy link
Member

adambor commented Dec 14, 2024

Why do we need this?

We want to support Starknet as part of our expansion to other chains.

Expected complexity

Very high

Comments

This will require:

  • rewriting the existing Solana contracts (atomiq-contracts-solana) into Cairo, and they should also already be built using the newly proposed modular architecture as described in Modularize smart contracts
  • creating a Starknet specific lib for atomiq (like our existing atomiq-chain-solana)
  • updating the front-end UX/UI to fully support connecting signers from multiple chains, such that the same front-end can be used for Starknet & Solana swaps

Reusability

N/A

@adambor
Copy link
Member Author

adambor commented Dec 16, 2024

Open questions for working with Starknet:

  • there are 2 sha256 invocations per bitcoin blockheader and up to 26 sha256 invocations per transaction SPV verification, how expensive is this in the starknet environment?
  • on Solana & EVM we save on storage costs by only storing hash commitments on-chain while emitting the full data as an event, does this make sense in starknet? If it does, which hash function is the cheapest to use for that hash commitment?
  • is there a standard way to verify account signatures on-chain (since starknet uses account abstraction)? Also, is there a standard used when signing arbitrary data?
  • how can we handle replay protection for signatures (we need a swap initialization to be cosigned by both participating parties)? On Solana we were able to re-use the native replay protection of transactions by having both signers cosign it. On Ethereum we are forced to rely on storing already initialized escrows forever, because we cannot reuse native replay protection - tx nonce is not available in EVM context (can we access the tx nonce in starknet contract?).
  • does it make sense to run a starknet node (I saw that it is not that resource hungry) with an external ethereum RPC provider? (i.e. is there any big gain in security, compared to the convinience of just using an externally managed RPC?)

@ob1337
Copy link

ob1337 commented Jan 6, 2025

Hey! Ohad from the StarkWare product team here. First, sorry for the long delay in getting back to you!

  1. I Forwarded the question internally, I hope to update you tomorrow
  2. Technically, calculating hashes (the cheapest one, Posidon, costs like 32 Cairo steps) is indeed cheaper than storage (hard to compare apples to apples because storage price comes from the Ethereum blob price). However, the storage size is also relatively modest (each storage element costs between the tiny fraction of a cent on low blob prices to around 0.5 cent when blob gas is around 100 gwei. Whenever blob prices become a bottleneck, we develop new features to tune down the cost further. So, if this optimization is worthwhile in your opinion, we would love to talk more, as we have concerns that using this design pattern might cause your code to be very complex.
  3. The fact that we have account abstraction doesn't mean we have no standardization. There are many account contracts developed (and soon audited) by Open Zepplin - here is an account that verifies Stark signature, and you may also find an account that verifies ETH signatures in the same directory. You may also look on repositories of Argent and Braavos, the Starknet native wallets, for more sophisticated logic that involves secp256r1 signing, multisigs, and more
  4. No, a nonce is not accessible from a transaction, but why not use a multi-signature account to guarantee this? To double down on my answer to (3), here is an Argent account that implements it
  5. We have many reputable provides such as Nethermind and Alchemy (blast), and AFAIK there was never a security breach in either of them. Long term this depends on the trust assumptions that you are willing to take.

@adambor
Copy link
Member Author

adambor commented Jan 6, 2025

Hey @ob1337 thanks for answering the questions!

  1. Technically, calculating hashes (the cheapest one, Posidon, costs like 32 Cairo steps) is indeed cheaper than storage (hard to compare apples to apples because storage price comes from the Ethereum blob price). However, the storage size is also relatively modest (each storage element costs between the tiny fraction of a cent on low blob prices to around 0.5 cent when blob gas is around 100 gwei. Whenever blob prices become a bottleneck, we develop new features to tune down the cost further. So, if this optimization is worthwhile in your opinion, we would love to talk more, as we have concerns that using this design pattern might cause your code to be very complex.

Alright, then this definitely seems like an over-optimization, we would just go with storing the data on-chain.

  1. The fact that we have account abstraction doesn't mean we have no standardization. There are many account contracts developed (and soon audited) by Open Zepplin - here is an account that verifies Stark signature, and you may also find an account that verifies ETH signatures in the same directory. You may also look on repositories of Argent and Braavos, the Starknet native wallets, for more sophisticated logic that involves secp256r1 signing, multisigs, and more

Is there a standard how to verify signature of the external account? I am looking for something like erc-1271 from the ethereum world. Also checking if there is any standard way to sign structured data, something like eip-712 in ethereum.

  1. No, a nonce is not accessible from a transaction, but why not use a multi-signature account to guarantee this? To double down on my answer to (3), here is an Argent account that implements it

I think using multi-signature account just adds more complexity, because that would imply a separate transaction that's required to fund the multi-signature account in the first place, and then also have a timeout mechanism in case one of the parties don't sign.

Btw, it seems like you should be able to get the nonce from the ExecutionInfo struct as TxInfo, just to make sure, does every wallet (due to account abstraction) use nonces (i.e. there is no nonce abstraction)?

  1. We have many reputable provides such as Nethermind and Alchemy (blast), and AFAIK there was never a security breach in either of them. Long term this depends on the trust assumptions that you are willing to take.

Alright, makes sense, so for now we just go with external RPCs and re-evaluate in the future.

@ob1337
Copy link

ob1337 commented Jan 8, 2025

  1. (The answer I owe you) - the cost of sha256 (512 bits) will be equivalent to 8k steps after version 0.13.4 (mainnet early April), given your seirra version is higher than 2.10 (compiler version > 1.7). The cost before that might be higher, up to 64k steps
  2. Sure, account contracts on starknet almost always implement the is_valid_signature and execute_from_outside calls which verify the account signature on a message, allowing meta transactions and paymasters. The message structure indeed follows EIP712
  3. I'm not sure what is your exact model so I could be wrong, but I don't think this will be complicated. Notice that with account abstraction the multisig account itself can send transactions so you don't need to fund it externally (unless this is a multisig that you set up each time in the context of a specific transactions)? Other things you may do to protect from replay could be to sign on an applicative nonce (so you will have another nonce with is just a regular app variable and you will refer to it), and/or sign on latest execution time which will be checked on-chain to avoid store-now-and-submit-next-year kind of attack

@adambor
Copy link
Member Author

adambor commented Jan 12, 2025

Hey @ob1337 thanks you for the answers!

  1. (The answer I owe you) - the cost of sha256 (512 bits) will be equivalent to 8k steps after version 0.13.4 (mainnet early April), given your seirra version is higher than 2.10 (compiler version > 1.7). The cost before that might be higher, up to 64k steps

That's a nice improvement, can I already deploy a contract using sierra 2.10 on mainnet and then enjoy the discount as soon as it comes, or is sierra 2.10 not yet supported and I would have to redeploy the contracts when 0.13.4 goes live?

Also I've run into some issues using scarb 2.10.0-rc0, specifically with openzeppelin libs:

- openzeppelin_access v0.20.0 cannot use starknet v2.10.0-rc.0 (std), because openzeppelin_access requires starknet ^2.9.1
- openzeppelin_account v0.20.0 cannot use starknet v2.10.0-rc.0 (std), because openzeppelin_account requires starknet ^2.9.1
- openzeppelin_introspection v0.20.0 cannot use starknet v2.10.0-rc.0 (std), because openzeppelin_introspection requires starknet ^2.9.1
- openzeppelin_token v0.20.0 cannot use starknet v2.10.0-rc.0 (std), because openzeppelin_token requires starknet ^2.9.1
- openzeppelin_utils v0.20.0 cannot use starknet v2.10.0-rc.0 (std), because openzeppelin_utils requires starknet ^2.9.1

Which is weird, because IMO ^2.9.1 should accept 2.10.0-rc.0 - maybe it's because of the leading "v"?

  1. Sure, account contracts on starknet almost always implement the is_valid_signature and execute_from_outside calls which verify the account signature on a message, allowing meta transactions and paymasters. The message structure indeed follows EIP712

Alright, that works, found an openzeppelin lib for SNIP12, and implemented SNIP6 signature checking with is_valid_signature call.

  1. I'm not sure what is your exact model so I could be wrong, but I don't think this will be complicated. Notice that with account abstraction the multisig account itself can send transactions so you don't need to fund it externally (unless this is a multisig that you set up each time in the context of a specific transactions)? Other things you may do to protect from replay could be to sign on an applicative nonce (so you will have another nonce with is just a regular app variable and you will refer to it), and/or sign on latest execution time which will be checked on-chain to avoid store-now-and-submit-next-year kind of attack.

Eventually I ended up just storing the already created escrows indefinitely (i.e. as used nonces), is there even any refund on starknet for clearing out storage?

I also wanted to ask one more question, in regards to using call_contract_syscall with error handling, in the docs it says that it is not yet supported as of starknet 0.13.2, is there any timeline in place as to when will this become available? We wanted to add a feature allowing the user to specify arbitrary external calls when escrow is successfully claimed (of course this will be isolated in separate execution proxy contract), such that the funds can be automatically staked, put into LP pool, or swapped. This of course doesn't work if we cannot catch an error, because the escrow might end up being "bricked" & unclaimable if the call fails (i.e. due to too tight slippage tolerance for swap).

@adambor
Copy link
Member Author

adambor commented Jan 17, 2025

Hey @ob1337, just bumping this and adding one more question, also I've already figured that I would need to wait for starknet 0.13.4 to be able to deploy Sierra 2.10 contracts, so you can disregard that question.

I want to ask if it is possible to do a conditional compilation based on feature flags, such that some part of the code is skipped, or inserted, I've figured (based on snforge book) I can conditionally compile whole modules or functions, but it doesn't state anything about conditionally compiling blocks of code, such as single if statements - this works in rust with #[cfg(not(feature = "feature_name"))] & #[cfg(feature = "feature_name")] macros. I basically need to have different execution path (skipped condition) when testing. Or is it possible to create 2 functions with the same name, such that one will compile when testing (e.g. with a feature flag) and other will compile when that feature flag is not present?

@ArielElp
Copy link

ArielElp commented Jan 19, 2025

That's a nice improvement, can I already deploy a contract using sierra 2.10 on mainnet and then enjoy the discount as soon as it comes, or is sierra 2.10 not yet supported and I would have to redeploy the contracts when 0.13.4 goes live?

2.10.0 is the Cairo version, Sierra is 1.7.0 (each compiler/Scarb version is associated with a Sierra version).
It's not yet deployable on Mainnet, as it's coupled to the Starknet v0.13.4 upgrade. Testnet will be upgraded in ~1 month and Mainnet sometime in March.

Which is weird, because IMO ^2.9.1 should accept 2.10.0-rc.0 - maybe it's because of the leading "v"?

I think RC versions are not considered greater than stable ones hence this is expected. The final 2.10.0 will be released in 1-2 weeks (it will be out before the testnet upgrade).

is there even any refund on starknet for clearing out storage?

No

I also wanted to ask one more question, in regards to using call_contract_syscall with error handling

Will be possible from v0.13.4 (Feb/March for Testnet/Mainnet).

Or is it possible to create 2 functions with the same name, such that one will compile when testing (e.g. with a feature flag) and other will compile when that feature flag is not present?

It's possible, see the gas example in the corelib, though TBH I'm not sure if it's the best way to do it. Sounds like 2 impls of some trait, one used for testing and the other in the actual contract, would be more fitting, but I don't really have enough context.

@adambor
Copy link
Member Author

adambor commented Jan 20, 2025

Thank you for the info!

It's possible, see the gas example in the corelib, though TBH I'm not sure if it's the best way to do it. Sounds like 2 impls of some trait, one used for testing and the other in the actual contract, would be more fitting, but I don't really have enough context.

Did something similar here, got 2 functions with the same where one is used in with "release" feature another one with "test", not the cleanest, but works. It might actually make sense to put some examples for this into the docs, I think it is pretty common to have slightly different functionality with different feature flags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants