Skip to content

Commit

Permalink
Added sweep batching contract, debugging actions flow
Browse files Browse the repository at this point in the history
  • Loading branch information
OxideDall committed Jan 22, 2025
1 parent 39b1366 commit 3c7433c
Show file tree
Hide file tree
Showing 28 changed files with 702 additions and 1,095 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
RPC_URL=https://rpc.superposition.so
WSS_URL=wss://rpc.superposition.so
INFRA_MARKET_ADDRESS=
BATCH_SWEEPER_ADDRESS=
ACTOR_PRIVATE_KEY=

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules
.env
src/types/contracts/
service/types/contracts/
dist/
out/
cache/
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2024 Fluidity Labs

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
70 changes: 14 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,24 @@
## Foundry
# Sweeper - 9Lives Protocol Automation

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**
Sweeper is a service that automates certain on-chain logic for the 9Lives protocol, an Arbitrum Stylus smart contract ecosystem using a factory/pair pattern. It helps manage events like call, whinge, declare, close, sweep, and escape, reducing manual overhead.

Foundry consists of:
## Main Components

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

https://book.getfoundry.sh/
• Infra Market Handler: An event-driven class that listens for on-chain events (e.g., MarketCreated2, CallMade, CommitmentRevealed) and orchestrates state transitions for campaigns.
• TxQueue: A queue system that batches and sends transactions to the chain (e.g., close, declare, sweepBatch).
• BatchSweeper : An optional contract-based approach to mass-slashing incorrectly betting users without multiple sequential calls.

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```
-

### Cast
#### TODO:

```shell
$ cast <subcommand>
```
- [ ] Solve sweeping epoch quering
- [ ] Rewrite tests on forge using ffi
- [ ] Prepare Dockerfile
- [ ] Extend Usage section of Readme

### Help
## License

```shell
$ forge --help
$ anvil --help
$ cast --help
```
See LICENSE file for details.
4 changes: 4 additions & 0 deletions abigen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
for file in contracts/*.sol; do
forge inspect $file:$(basename ${file%.*}) abi > service/abi/$(basename ${file%.*}).json
done

33 changes: 33 additions & 0 deletions contracts/BatchSweeper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IInfraMarket} from "./IInfraMarket.sol";

contract BatchSweeper {
/**
* Calls sweep method on the infra-market for each
* address from the victims array.
*
* @param infraMarket InfraMarket contract address
* @param tradingAddr Specific campaign/trading address
* @param epochNo Epoch number from your contract
* @param victims List of "guilty" addresses that need to be "swept"
* @param feeRecipient Who receives possible fees
*/
function sweepBatch(
address infraMarket,
address tradingAddr,
uint256 epochNo,
address[] calldata victims,
address feeRecipient
) external {
for (uint256 i = 0; i < victims.length; i++) {
IInfraMarket(infraMarket).sweep(
tradingAddr,
epochNo,
victims[i],
feeRecipient
);
}
}
}
242 changes: 242 additions & 0 deletions contracts/IInfraMarket.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IInfraMarket {
enum InfraMarketState {
Callable,
Closable,
Whinging,
Predicting,
Revealing,
Declarable,
Sweeping,
Closed
}

function ctor(
address operator,
address emergencyCouncil,
address lockup,
address lockedArbToken,
address factory
) external;

/**
* @notice Register this campaign, taking a small stipend for management from the
* creator in the form of $3 fUSDC. Factory caller only.
* @param trading address to configure this
* @param desc of the contract to commit as info for users. Should be info for a oracle.
* @param launchTs to use as the timestamp to begin this infra market.
* Could be the conclusion date.
* @param callDeadlineTs, the last date that this should decide an outcome before
* entering into an emergency state.
*/
function register(
address trading,
bytes32 desc,
uint64 launchTs,
uint64 callDeadlineTs
) external returns (uint256);

/**
* @notice Call the outcome, changing the state to allow a user to disagree
* with it with the whinge function. Takes a $2 fUSDC bond.
* @param tradingAddr to call for.
* @param winner to indicate is the preferred outcome by this user.
* @param incentiveRecipient to send future incentive amounts, and the refund
* for the bond to.
*/
function call(
address tradingAddr,
bytes8 winner,
address incentiveRecipient
) external returns (uint256);

/**
* @notice Whinge the outcome, indicating that the sender disagrees with the call
* decision that was made. This is only possible during a two day window.
* A $7 fUSDC must be taken from the user.
* @param tradingAddr to use for the disagreement that's taking place.
* @param preferredOutcome to use as the outcome that the whinger disagrees is
* the best.
* @param bondRecipient to send the bond that's refunded back to.
*/
function whinge(
address tradingAddr,
bytes8 preferredOutcome,
address bondRecipient
) external returns (uint256);

/**
* @notice Make a commitment as to what the preferred outcome should be, now
* that there's been calling and whinging. The voting power comes from
* the lockup contract, which takes ARB and locks it up for an amount
* of time that this trading should close.
* @param tradingAddr to use as the trading address to make commitments for.
* @param commit to use as the commitment for what the outcome should be.
*/
function predict(address tradingAddr, bytes32 commit) external;

/**
* @notice Get the amount of vested ARB in a specific outcome produced by
* reveals up until now.
* @param trading contract this is for.
* @param outcome that we want to know.
*/
function curOutcomeVestedArb(
address trading,
bytes8 outcome
) external view returns (uint256);

/**
* @notice Reveal a previously made commitment. Should be done in the revealing
* period (two days after the first whinge, for two days).
* @param tradingAddr to use as the place for the commitments to be tracked.
* @param committerAddr to use as the address of the user making commitments.
* @param outcome to state the previously made commitment was for.
* @param seed to use as the random nonce for the reveal.
*/
function reveal(
address tradingAddr,
address committerAddr,
bytes8 outcome,
uint256 seed
) external;

/**
* @notice Sweep money from a bettor who bet incorrectly, or someone who neglected to
* reveal their commitment, who is assumed to be betting that the system
* is in an indeterminate state.
* @param tradingAddr to use as the trading address for the campaign.
* @param epochNo to use as the epoch number to take funds from.
* @param victim to claim funds from.
* @param feeRecipientAddr to send the small amount taken from the victim to (1%).
*/
function sweep(
address tradingAddr,
uint256 epochNo,
address victim,
address feeRecipientAddr
) external returns (uint256 yieldForFeeRecipient);

/**
* @notice Capture amounts from the prize pool. Can only be done once, so be careful!
* @param tradingAddr to capture amounts from.
* @param epochNo to collect amounts from the pot from.
* @param feeRecipient to send incentive amounts to.
*/
function capture(
address tradingAddr,
uint256 epochNo,
address feeRecipient
) external returns (uint256 yieldForFeeRecipient);

/**
* @notice Close this campaign if it's been in a state where anyone can whinge for
* some time, two days since someone whinged and no-one had whinged.
* @param tradingAddr this market is for.
* @param feeRecipient to send the incentive for closing to.
*/
function close(address tradingAddr, address feeRecipient) external;

/**
* @notice Escape a trading market that has gone over the limit. This calls
* the escape function in the trading contract to indicate something
* has gone wrong. This should only be callable if the contract is in the
* state for calling past the deadline.
* @param tradingAddr to escape.
*/
function escape(address tradingAddr) external;

/**
* @notice Winner that was declared for this infra market, if there is one.
*/
function winner(
address tradingAddr
) external view returns (bytes8 winnerId);

/**
* @notice Status of this trading contract's oracle.
*/
function status(
address tradingAddr
)
external
view
returns (InfraMarketState currentState, uint64 secsRemaining);

/**
* @notice Starting timestamp of the campaign.
*/
function startTs(address trading) external view returns (uint64);

/**
* @notice Ending timestamp of the campaign.
*/
function endTs(address trading) external view returns (uint64);

/**
* @notice Declare a winner, by providing the outcomes that were in use, along
* with a fee recipient to collect the fee for providing this correct calldata
* to.
* @param tradingAddr to use as the trading address for the campaign.
* @param outcomes to use as the outcomes that were in use.
* @param feeRecipient to send the incentive for declaring to.
*/
function declare(
address tradingAddr,
bytes8[] calldata outcomes,
address feeRecipient
) external returns (uint256);

/**
* @notice Enable or disable the contract.
* @param status to set the contract to.
*/
function enable_contract(bool status) external returns (bool);

event InfraMarketEnabled(bool indexed status);

event MarketCreated2(
address indexed incentiveSender,
address indexed tradingAddr,
bytes32 indexed desc,
uint64 launchTs,
uint64 callDeadline
);

event CallMade(
address indexed tradingAddr,
bytes8 indexed winner,
address indexed incentiveRecipient
);

event InfraMarketClosed(
address indexed incentiveRecipient,
address indexed tradingAddr,
bytes8 indexed winner
);

event DAOMoneyDistributed(
uint256 indexed amount,
address indexed recipient
);

event Committed(
address indexed trading,
address indexed predictor,
bytes32 indexed commitment
);

event CommitmentRevealed(
address indexed trading,
address indexed revealer,
bytes8 indexed outcome,
address caller,
uint256 bal
);

/// @notice CampaignEscaped, because a campaign is in an
/// indeterminate state! The DAO may be needed to step in.
event CampaignEscaped(address indexed tradingAddr);
}
1 change: 0 additions & 1 deletion contracts/MassSweeper.sol

This file was deleted.

7 changes: 3 additions & 4 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[profile.default]
src = "src"
src = "contracts"
out = "out"
libs = ["node_modules"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
libs = ["lib"]
test = "test"
Loading

0 comments on commit 3c7433c

Please sign in to comment.