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

Switch to FT-141 for BridgeToken #39

Merged
merged 22 commits into from
Mar 12, 2021
Merged

Switch to FT-141 for BridgeToken #39

merged 22 commits into from
Mar 12, 2021

Conversation

ilblackdragon
Copy link
Contributor

@ilblackdragon ilblackdragon commented Mar 4, 2021

Implements basics of FT-141.
Sim tests are still not finished and everything should be looked over again to see if there are better flows (like react on receiving to factory_id for withdrawing tokens)

bridge-token/src/lib.rs Outdated Show resolved Hide resolved
bridge-token/src/lib.rs Outdated Show resolved Hide resolved
@ilblackdragon
Copy link
Contributor Author

Filled the bug found in near-sdk-rs: near/near-sdk-rs#306

@alexauroradev
Copy link

Fixes #39

@alexauroradev alexauroradev self-requested a review March 4, 2021 22:12
bridge-token-factory/src/lib.rs Outdated Show resolved Hide resolved
bridge-token-factory/src/lib.rs Outdated Show resolved Hide resolved
bridge-token/src/lib.rs Outdated Show resolved Hide resolved
@sept-en
Copy link
Contributor

sept-en commented Mar 5, 2021

This PR fixes #21.

Leverage rust enum types for better interface of ResultType
Formatting
@mfornet
Copy link
Contributor

mfornet commented Mar 5, 2021

Right now mint always require attached a NEAR deposit, but there are several options:

  1. Do nothing => mint always require attached $N (1 yoctoNear is fine if no registration is needed, but then FullAccessKey signature is required)
  2. Have two functions, one to register (also one to unregister) and one for minting. Only register and unregister are payable, but mint isn't.
  3. Have two mint functions (one that is payable and allows registration, and one that is not payable but require user to be already registered).

If in addition there is a view function that allows UI to know in advance whether the user is registered or not we can improve UX for options 2 and 3. However they still need to first sign tx to register with FullAccessKey, and then add extra key to call non-payable mint function.

.try_to_vec()
.unwrap(),
);
PromiseOrValue::Value(amount)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be 0 given that we are locking all those tokens on this contract?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right, should be 0

@ilblackdragon
Copy link
Contributor Author

Is payable actually requires that at least 1 yN gets attached?

Have separate functions

There is a pure storage registration function already in the token, but it's more of a question if user or relayer needs to call it or can just call mint once.
Also note, need to get this PR into near-sdk-rs: near/near-sdk-rs#309 to make sure API is compatible.

@ilblackdragon
Copy link
Contributor Author

ilblackdragon commented Mar 5, 2021 via email

@ilblackdragon
Copy link
Contributor Author

ilblackdragon commented Mar 5, 2021 via email

@mfornet
Copy link
Contributor

mfornet commented Mar 5, 2021

@ilblackdragon what contract did you deployed, because in this repository I got this:

❯ ls -l res/bridge_token_factory.wasm
-rwxr-xr-x  1 marcelo  staff  3769047 Mar  5 14:14 res/bridge_token_factory.wasm

This contract is 3769047 bytes long. Is it possible that you deployed old version of the contract? Use latest commit in this PR.

@ilblackdragon
Copy link
Contributor Author

ilblackdragon commented Mar 8, 2021 via email

@alexauroradev
Copy link

alexauroradev commented Mar 8, 2021

Please update to the new interface of Storage Manger: https://github.com/near/near-sdk-rs/blob/master/near-contract-standards/src/storage_manager/mod.rs
Plus, use https://github.com/near/near-sdk-rs/blob/master/near-contract-standards/src/fungible_token/implementation.rs#L56 field to implement storage_minimum_balance

@mikedotexe, the current version of the vanilla token implementation still uses AR instead of a storage manger. Is this something that is going to continue? We need the interface for the storage interaction for mint function

CC: @mfornet

@alexauroradev
Copy link

Closes #21

@alexauroradev
Copy link

alexauroradev commented Mar 8, 2021

@alexauroradev
Copy link

@mfornet
Need also to add here an assert that the transaction has enough attached deposit to pay for the storage (in case the account is not created). If we're not doing this then the user will lose the proof, if he didn't attach enough deposit (see self.record_proof()).

@alexauroradev
Copy link

Need also to add here an assert that the transaction has enough attached deposit to pay for the storage (in case the account is not created). If we're not doing this then the user will lose the proof, if he didn't attach enough deposit (see self.record_proof()).

This is much more complicated problem due to the fact of async execution of the contracts, as was mentioned by @abacabadabacaba.

Scenario when the asserts are not working :

  • Bridge factory checks that there's a user account, so no attached_deposit required
  • Bridge schedules a minting call to the bridge token
  • Just before this, a user withdraws all the amount of tokens and deletes the account using storage_unregister here.
  • Once the initial minting call reaches a factory, there're already no account and no attached_deposit, so the mint fails.

As a result, the proof was consumed, while the transfer was not finished. Recording the proof consumption after the minting function execution is not working, since then one proof can be used multiple times.

One of the possible option is to add a rollback procedure for the proof recordings. In this case the proof should be forwarded to mint and in case it fails, we need to call a new rollback_proof method with the proof.

CC @mfornet @abacabadabacaba

@mfornet
Copy link
Contributor

mfornet commented Mar 9, 2021

@djsatok my understanding from how the runtime works, is that if a promise fails, the full transaction is reverted, so the call to record_proof is also reverted. If there is not enough funds attached for the mint function, then it will fail and the whole deposit transaction is reverted.

  • Bridge factory checks that there's a user account, so no attached_deposit required

Bridge factory doesn't check this, this is checked on the BridgeToken once the mint function is called.

@mfornet
Copy link
Contributor

mfornet commented Mar 9, 2021

After reading this SO answer I see the whole transaction is not reverted.

One possible solution is to record the proof on the BridgeToken instead of storing it on the factory. We pass the proof to mint and verify storage deposit is enough to have the account and to store the proof. In this case the function storage_balance_bounds from StorageManagement on BridgeToken will have unbounded upperbound.

@abacabadabacaba @djsatok

@alexauroradev
Copy link

Discussed the above mentioned issue with reverting the deposit transaction. Agreed solution is to require the attachmend of enough $NEAR to cover the storage of the proof and the creation of a new account (even if the account already exists). The appropriate assert should be added to the deposit method.

Perhaps in future we should implement the reverting mechanism, though it would still have some places to shoot in a leg, like attaching enough gas to pay for the reverting receipt.

@abacabadabacaba
Copy link
Contributor

Shouldn't we call mint with fixed amount of gas? Otherwise, a malicious user may attach too little gas to make it revert while the proof is still recorded.

@mfornet
Copy link
Contributor

mfornet commented Mar 10, 2021

Shouldn't we call mint with fixed amount of gas? Otherwise, a malicious user may attach too little gas to make it revert while the proof is still recorded.

Done here

Notice the restriction is even higher. We enforce the attached deposit should be enough to register the account on the BridgeToken (even if it is already registered). Deposit that is not used is refunded to the signer on the BridgeToken contract.

Disregard previous comment, I read attached deposit instead of attached gas.

@mfornet
Copy link
Contributor

mfornet commented Mar 10, 2021

Shouldn't we call mint with fixed amount of gas? Otherwise, a malicious user may attach too little gas to make it revert while the proof is still recorded.

  • Either we enforce a minimum amount of gas (which should be enough for the worst case)
  • or we assert that only the recipient of the transaction can call the method.

The drawback of the second approach, is that right now we currently don't require the recipient to even exist, and that won't be the case anymore.

@abacabadabacaba
Copy link
Contributor

Why not just call mint with fixed amount of gas which should be enough? If there is not enough gas in finish_deposit for this, it will fail and the proof will not be recorded.

@abacabadabacaba
Copy link
Contributor

Also, I see that this PR removes lock functions. Why doesn't it also remove unlock functions? These functions are useless without each other, aren't they?

@@ -11,7 +11,7 @@ docker run \
-w /host/bridge-token-factory \
-e RUSTFLAGS='-C link-arg=-s' \
nearprotocol/contract-builder \
cargo +stable build --target wasm32-unknown-unknown --release
/bin/bash -c "rustup target add wasm32-unknown-unknown; cargo build --target wasm32-unknown-unknown --release"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this needed?

Copy link
Contributor

Choose a reason for hiding this comment

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

wasm32-unknown-unknown is not installed in the current docker image for the latest toolchain. Notice it haven't been updated for 8 months. The Dockerfile is correct but we need to publish the new image. Filed issue at near/near-sdk-rs#310

The error I'm getting right now:

   Compiling bridge-token-factory v0.1.0 (/host/bridge-token-factory)
error[E0463]: can't find crate for `std`
  |
  = note: the `wasm32-unknown-unknown` target may not be installed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.
error: could not compile `bridge-token-factory`.


const NO_DEPOSIT: Balance = 0;

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add PanicOnDefault to BridgeTokenFactory as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done: 48eeea8

decimals: Option<u8>,
) {
// Only owner can change the metadata
assert_eq!(env::current_account_id(), env::signer_account_id());
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't using signer_account_id have the same problems as using tx.origin in Solidity? Please change to predecessor_account_id.

Copy link
Contributor

Choose a reason for hiding this comment

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

Solved in 7482c5d

Moreover same issue existed with current implementation of AdminControlled which is fixed here: Near-One/rainbow-bridge#524. It is already fixed, and added PR to use respective version: dbc227b

recipient,
&self.controller,
NO_DEPOSIT,
env::prepaid_gas() / 2,
Copy link
Contributor

Choose a reason for hiding this comment

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

This may run out of gas, in which case the tokens will be destroyed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done d0b92af

Together with fixed gas to schedule finish_withdraw / finish_deposit / mint

)
};
}

#[test]
fn test_eth_token_transfer() {
let (user, factory) = setup_token_factory();
let root = "root".to_string();
Copy link
Contributor

Choose a reason for hiding this comment

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

This variable is redundant and is not used.

Copy link
Contributor

Choose a reason for hiding this comment

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

Solved in 3bd8556

Copy link
Contributor

@abacabadabacaba abacabadabacaba left a comment

Choose a reason for hiding this comment

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

LGTM

@mfornet mfornet merged commit d602235 into master Mar 12, 2021
@mfornet mfornet deleted the ft-141 branch April 20, 2021 18:11
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.

5 participants