Skip to content

Commit

Permalink
Merge pull request #348 from oasisprotocol/kostko/feature/rofl
Browse files Browse the repository at this point in the history
contracts: Add ROFL subcall rofl.IsAuthorizedOrigin
  • Loading branch information
kostko authored Aug 20, 2024
2 parents 1f7939f + 7a031ec commit 85c08a3
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 1 deletion.
26 changes: 26 additions & 0 deletions contracts/contracts/Subcall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ enum SubcallReceiptKind {
* @notice Interact with Oasis Runtime SDK modules from Sapphire.
*/
library Subcall {
// Consensus
string private constant CONSENSUS_DELEGATE = "consensus.Delegate";
string private constant CONSENSUS_UNDELEGATE = "consensus.Undelegate";
string private constant CONSENSUS_WITHDRAW = "consensus.Withdraw";
string private constant CONSENSUS_TAKE_RECEIPT = "consensus.TakeReceipt";
// Accounts
string private constant ACCOUNTS_TRANSFER = "accounts.Transfer";
// ROFL
string private constant ROFL_IS_AUTHORIZED_ORIGIN =
"rofl.IsAuthorizedOrigin";

/// Address of the SUBCALL precompile
address internal constant SUBCALL =
Expand All @@ -42,6 +47,9 @@ library Subcall {

error AccountsTransferError(uint64 status, string data);

/// The origin is not authorized for the given ROFL app
error RoflOriginNotAuthorizedForApp();

/// Name of token cannot be CBOR encoded with current functions
error TokenNameTooLong();

Expand Down Expand Up @@ -578,4 +586,22 @@ library Subcall {
revert AccountsTransferError(status, string(data));
}
}

/**
* @notice Verify whether the origin transaction is signed by an authorized
* ROFL instance for the given application.
* @param appId ROFL app identifier
*/
function roflEnsureAuthorizedOrigin(bytes21 appId) internal {
(uint64 status, bytes memory data) = subcall(
ROFL_IS_AUTHORIZED_ORIGIN,
abi.encodePacked(hex"55", appId) // CBOR byte string, 21 bytes.
);

// The result should be a CBOR-encoded boolean with the value true indicating
// that the origin is authorized for the given ROFL app.
if (status != 0 || data.length != 1 || data[0] != 0xf5) {
revert RoflOriginNotAuthorizedForApp();
}
}
}
4 changes: 4 additions & 0 deletions contracts/contracts/tests/SubcallTests.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ contract SubcallTests {
Subcall.consensusWithdraw(to, value);
}

function testRoflEnsureAuthorizedOrigin(bytes21 appId) external {
Subcall.roflEnsureAuthorizedOrigin(appId);
}

function testParseCBORUint(bytes memory result, uint256 offset)
external
pure
Expand Down
2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"format::prettier": "prettier --write --plugin-search-dir=. '*.json' '**/*.ts' '**/*.sol'",
"format": "npm-run-all format:**",
"build": "hardhat compile",
"test": "hardhat test --network sapphire-localnet"
"test": "hardhat test --network sapphire-localnet --verbose"
},
"files": [
"contracts"
Expand Down
20 changes: 20 additions & 0 deletions contracts/test/subcall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,26 @@ describe('Subcall', () => {
}
});

/// Verifies that the 'rofl.IsAuthorizedOrigin' operation can be executed
/// Currently it should always revert as there is no way to mock a ROFL app in tests.
it('rofl.IsAuthorizedOrigin', async () => {
const appId = getBytes(zeroPadValue(ownerAddr, 21));

// First test the raw subcall.
const msg = cborg.encode(appId);
let tx = await contract.testSubcall('rofl.IsAuthorizedOrigin', msg);
let receipt = await tx.wait();

if (!receipt) throw new Error('tx failed');
const event = decodeResult(receipt);
expect(event.status).eq(0n); // rofl.IsAuthorizedOrigin response status, 0 = success
expect(event.data).eq(false); // Boolean false to indicate failure.

// Also test the Subcall.roflEnsureAuthorizedOrigin wrapper.
tx = await contract.testRoflEnsureAuthorizedOrigin(appId);
await expect(tx).to.be.reverted;
});

describe('Should successfully parse CBOR uint/s', () => {
it('Should successfully parse CBOR uint8', async () => {
const MAX_SAFE_UINT8 = 255n;
Expand Down

0 comments on commit 85c08a3

Please sign in to comment.