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

MD-14 #14

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions MD/md-14/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# MD-14: Bridge Should Use A More Secure Timelock
- **Description**: Provide formal structure for proposing non-trivial improvements to Movement.
- **Authors**: [Primata](mailto:[email protected])

## Overview

The Bridge is arguably the most important feature of an L2 and lately we have had a confusing approach to it. We might want to solidify our understanding of how it is to be used and the assumptions we rely on. Off-loading the Bridge Relayer from securing timestamps might be important here in terms of security and preventing it from being an attack vector.

## Definitions

* Timelock - Time delta between the current block time and the end-of-lock time.
* Bridge Relayer - formerly referred as the bridge service, it's the infrastructure utilized to have some form of synchronicity of the bridge request state. Single point of failure.
* Initiator Contract - Contract the user utilizes to initialze the bridge and the bridge relayer completes or refunds the user. Exists both on Ethereum and Movement.
* Counterparty Contract - Contract the user completes the bridge and the bridge relayer locks or cancels the bridge. Exists both on Ethereum and Movement.


## Desiderata

1.
2. Because it has to be lower than the Initiator Contract Timelock, whenever Timelock is consumed, it is consumed as `timelock`.
3. Definitely use timestamps for the sake of synchronicity between Ethereum and Movement.
4. Remove dependency of the Bridge Relayer on processing the desired timelock.

### D1: Initiator Contract Timelock is a constant or a modifiable state with a minimum time
**User Journey**: Whenever Timelock is consumed, it is consumed as `timelock * 2`. If a modifiable state, it should be at least 12 hours.
Copy link
Contributor

Choose a reason for hiding this comment

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

So, the idea here is to not relay any timestamp information in, right?

Instead we simply assume the bridge relay has sent the time-lock information over as quickly as it can and use the timestamp from the destination chain when the relay transaction is received.

This removes the trust on any clock in the bridge service, thus making it harder to manipulate.

The tradeoff is perhaps that the attacker can now attack by forcing delays on the bridge. But, these could be easier to detect than lock manipulations.

Copy link
Author

Choose a reason for hiding this comment

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

This is one reason why we need a minimum time bound. Maybe an upper bound might be necessary just so that a user couldn't have funds stuck in the bridge for type(uint).max time

Copy link
Contributor

Choose a reason for hiding this comment

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

As in the difference between the reported timestamp and the timestamp at the time the relay transaction is received?

Copy link
Author

@0xPrimata 0xPrimata Sep 5, 2024

Choose a reason for hiding this comment

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

timelock = 20
initiator receiving a bridge at time 0
counterparty lock is called at 5
initiator completes at 10
counterparty completes at 15

It would be an issue if:
iinitiator receiving a bridge at time 0
counterparty lock is called at 21
counterparty completes at 40
initiator cancels at 41

This is already an issue with the current implementation if the Bridge Relayer fails at some certain levels.

Copy link
Contributor

Choose a reason for hiding this comment

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

minimum time bound

Only makes sense when you have quite short timelocks and the actual act of calling over the network could cause them to expire incorrectly.


**Justification**: Because it has to be higher than the Counterparty Contract Timelock, `timelock * 2` is reasonable. A modifiable state should have some form to prevent malicious attacks. If lowering becomes a necessity, an upgrade to the contract will solve the issue. `timelock * 2` consumption also introduces a requirement from the design which stipulates that the initiator timelock has to be significantly higher than the counterparty to assure that a bridge transfer cannot be completed on the target chain and cancelled on the origin chain.

### D2: Counterparty Contract Timelock is a constant or a modifiable variable with a minimum time
**User Journey**: Bridge Relayer locks the bridge transfer on the Counterparty side. It does not specify the timelock. The timelock is specified by the timelock state or constant in the Ethereum Initiator Contract or Movement Initiator Contract.

**Justification**: Because it has to be higher than the Counterparty Contract Timelock, `timelock` is reasonable. A modifiable state should have some form to prevent malicious attacks. If lowering becomes a necessity, an upgrade to the contract will solve the issue.

### D3: Use timestamps instead of block number
0xPrimata marked this conversation as resolved.
Show resolved Hide resolved
**User Journey**: This has already been agreed, but by using timestamp, there is no necessity to handle block.number parity between chains.

**Justification**: For cross bridge synchronocity between Ethereum and Movement which have very distinct block numbers and block settlement speed.
0xPrimata marked this conversation as resolved.
Show resolved Hide resolved

### D4: Remove dependency of the Bridge Relayer on processing the desired timelock.
**User Journey**: Bridge Relayer stops having any decision how the timelock timestamp. It is fully provided by the contracts and modules variables.

**Justification**: We are heavily relying on the Bridge Relayer's capabilities to not fail and this should make the Bridge Relayer less error prone.


**Guidance and suggestions**:

Ethereum contracts:
```
uint256 public timelock = 1 days;
...
function setTimelock (uint256 newTimelock) external onlyOwner {
if (newTimelock < 12 hours) revert MinimumTimelockError();
timelock = newTimelock;
}
```
Movement Modules:
```
struct BridgeConfig has key {
moveth_minter: address,
bridge_module_deployer: address,
signer_cap: account::SignerCapability,
timelock: u64
}
...
move_to(resource,BridgeConfig {
moveth_minter: signer::address_of(resource),
bridge_module_deployer: signer::address_of(resource),
signer_cap: resource_signer_cap,
timelock: 12 hours
});
```

handle consumption depending on the condition on if it's an initiator or a counterparty

## Errata