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

NONEVM-298: timelock contract #528

Merged
merged 6 commits into from
Oct 1, 2024
Merged

Conversation

augustbleeds
Copy link
Collaborator

@augustbleeds augustbleeds commented Sep 25, 2024

This is the last set of contract changes necessary for the upcoming audit. There are some optional contract changes as well we can add further down the road.

  • timelock contract (it implements the SRC-5 standard (since we are on Starknet instead of EVM), which is similar to the EIP-165 standard for knowing if a contract adheres to supports certain interfaces. in this case, timelock on EVM is EIP-165 compatible because it needs to be able to perform safe transfers of certain standards of tokens)
  • enumerable set component (encapsulates set-related functionality)

data: Span<felt252>,
}

fn _hash_operation_batch(calls: Span<Call>, predecessor: u256, salt: u256) -> u256 {
Copy link
Contributor

Choose a reason for hiding this comment

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

im not across the latest Cairo standards, why does this need to be split out into its own fn outside of the module?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it doesn't. I split it out so that it could be used as a utility function in tests. I didn't end up using it though

}

fn _execute(ref self: ContractState, call: Call) {
let _response = call_contract_syscall(call.target, call.selector, call.data)
Copy link
Contributor

Choose a reason for hiding this comment

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

does the response contain any useful information? if not, is there any point in assigning it to a variable (or is this a linter thing?)

Comment on lines 376 to 392
fn update_delay(ref self: ContractState, new_delay: u256) {
self.access_control.assert_only_role(ADMIN_ROLE);

self
.emit(
Event::MinDelayChange(
MinDelayChange {
old_duration: self._min_delay.read(), new_duration: new_delay,
}
)
);
self._min_delay.write(new_delay);
}

//
// ONLY ADMIN
//
Copy link
Contributor

Choose a reason for hiding this comment

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

update_delay should be under ONLY ADMIN as well right

assert(!mock.contains(MOCK_SET_ID, 300), 'does not contain 300');
assert(mock.contains(MOCK_SET_ID, 200), 'contains 200');
assert(mock.at(MOCK_SET_ID, 1) == 200, 'indexes match');
assert(mock.at(MOCK_SET_ID, 2) == 0, 'no entry at 2nd index');
Copy link
Contributor

Choose a reason for hiding this comment

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

an interesting behaviour of this enumerable set implementation - you wouldn't be able to tell if the entry at an index is actually zero or if there is no entry?

Copy link
Collaborator Author

@augustbleeds augustbleeds Sep 27, 2024

Choose a reason for hiding this comment

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

yeah, you can't store the 0 value in this implementation. I guess I could solve for this by introducing a special map that only stores 0? EVM doesn't have this problem because storage values can be arrays (not the case in Starknet).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

actually, i think as long as i do a length check, we can assume that 0's retrieved from indexes less than or equal to the length are valid

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i fixed it so that .at() does a length check and panics if the index is invalid. that way if you get back a 0 from .at() it will be valid

assert(actual_toggle, 'toggle true');

assert(timelock.is_operation_done(id), 'operation is done');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

could also add another schedule/execute batch with predecessor = first batch to this test to demonstrate that works as intended too

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good point, i'll add that 👍

}
}

// snforge does not treat contract invocation failures as a panic (yet)
Copy link
Contributor

Choose a reason for hiding this comment

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

so executing this on a real environment would result in a panic? is the timelock contract able to tell which op failed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

in a real environment you'd get a panic / revert. in general, the EVM version also does not explictly tell you which operation failed

@cl-sonarqube-production
Copy link

Quality Gate passed Quality Gate passed

Issues
0 New issues
0 Fixed issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
No data about Duplication

See analysis details on SonarQube

@augustbleeds augustbleeds merged commit 4e597a9 into develop Oct 1, 2024
23 checks passed
@augustbleeds augustbleeds deleted the augustus.nonevm-298.timelock branch October 1, 2024 14:00
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