Omniscia Boson Protocol Audit

TokenTransferAuthorizationLib Code Style Findings

TokenTransferAuthorizationLib Code Style Findings

TTA-01C: BPIP-12 Encoding Mismatch of EIP-3009

Description:

The BPIP-12 document highlights that the EIP-3009 encoding path should have the from, to, and value variables encoded preceding the currently decoded variables which is inefficient.

Example:

contracts/protocol/libs/TokenTransferAuthorizationLib.sol
212function _consumeERC3009(address _token, address _from, address _to, uint256 _amount, bytes memory _data) private {
213 (uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s) = abi.decode(
214 _data,
215 (uint256, uint256, bytes32, uint8, bytes32, bytes32)
216 );
217 IERC3009(_token).receiveWithAuthorization(_from, _to, _amount, validAfter, validBefore, nonce, v, r, s);
218}

Recommendation:

We advise the BPIP-12 definition to be updated to match the implementation.

Alleviation (8fccc2716047809e4bc7786c95d346e5c61b2896):

The BPIP-12 definition was updated to match the decoding implementation, addressing this exhibit.

TTA-02C: BPIP-12 Strategy Support Mismatch

Description:

The BPIP-12 definition has not been updated to outline the newly introduced DAI-like permit support as part of the TTA-02M remediation efforts.

Example:

contracts/protocol/libs/TokenTransferAuthorizationLib.sol
196if (
197 strategy == BosonTypes.TokenTransferAuthorizationStrategy.EIP2612 ||
198 strategy == BosonTypes.TokenTransferAuthorizationStrategy.DAIPermit
199) {

Recommendation:

We advise the BPIP-12 to be updated, reflecting the latest state of the code.

Alleviation (aa4ed0861e282bd766a66dbb98c0883e81ec8db9):

The BPIP-12 standard was updated to properly illustrate DAI-like approval strategy support, addressing this exhibit in full.

TTA-03C: Inefficient Calldata-Memory Copy

Description:

The TokenTransferAuthorizationLib::loadQueue function will load the full _packed array into memory before processing each entry inefficiently.

Example:

contracts/protocol/libs/TokenTransferAuthorizationLib.sol
50function loadQueue(bytes calldata _packed) internal {
51 bytes[] memory queue = abi.decode(_packed, (bytes[]));
52
53 uint256 length = queue.length;
54 bytes32 lenSlot = LEN_SLOT;
55 bytes32 headSlot = HEAD_SLOT;
56 assembly {
57 tstore(lenSlot, length)
58 tstore(headSlot, 0)
59 }
60
61 for (uint256 i = 0; i < length; ++i) {
62 _storeEntry(i, queue[i]);
63 }
64}

Recommendation:

We advise each entry to be read directly from calldata, optimizing the code's gas cost.

Alleviation (8fccc2716047809e4bc7786c95d346e5c61b2896):

Queue loading was optimized to use a calldata pointer for the packed data, addressing this exhibit.

TTA-04C: Inefficient Iterator Increments

TypeSeverityLocation
Gas OptimizationTokenTransferAuthorizationLib.sol:
I-1: L92, L93, L97
I-2: L273, L274, L277

Description:

The w iterator on both code instances is inefficiently offset by 1 within the for loop body.

Example:

contracts/protocol/libs/TokenTransferAuthorizationLib.sol
92for (uint256 w = 0; w < numWords; ++w) {
93 bytes32 slot = bytes32(uint256(base) + 1 + w);
94 bytes32 word;
95 assembly {
96 word := tload(slot)
97 mstore(add(entry, mul(32, add(w, 1))), word)
98 }
99}

Recommendation:

We advise this 1 offset to be assimilated into the loop itself (i.e. uint256 w = 0; w <= numWords;...), optimizing each iteration's gas cost.

Alleviation (8fccc2716047809e4bc7786c95d346e5c61b2896):

The first instance of this exhibit was properly optimized whilst the second instance has retained its original structure due to the revisions required by calldata pointer usage which no longer require a 1 offset in the assembly block.

TTA-05C: Inefficient TLOAD Operations

Description:

The TokenTransferAuthorizationLib::consumeForTransfer function invokes its TokenTransferAuthorizationLib::hasQueue function and proceeds to invoke TokenTransferAuthorizationLib::popNext right after it, resulting in the LEN_SLOT being read from transient storage twice redundantly.

Example:

contracts/protocol/libs/TokenTransferAuthorizationLib.sol
181if (!hasQueue()) return false;
182
183bytes memory entry = popNext();

Recommendation:

We advise the data entry to be persisted across invocations, optimizing the code's gas cost and reducing the function's TLOAD calls by one.

Alleviation (8fccc2716047809e4bc7786c95d346e5c61b2896):

The code has been optimized to efficiently fetch the length once and pass it in as an argument, optimizing the code.

TTA-06C: Modifier-Style Usage Support

Description:

The TokenTransferAuthorizationLib structure indicates that every TokenTransferAuthorizationLib::loadQueue function call must be accompanied by a TokenTransferAuthorizationLib::clearQueue function call after the queue has been processed yet the contract trusts callers to use the library responsibly.

Example:

contracts/protocol/libs/TokenTransferAuthorizationLib.sol
114/**
115 * @notice Resets the queue's bookkeeping so a subsequent call in the same
116 * transaction sees no loaded queue. The metatransaction entry
117 * point that loaded the queue must call this at the end of its
118 * successful path; otherwise leftover entries (e.g. when the
119 * inner call consumed fewer entries than the queue carried) would
120 * persist in transient storage and be popped by an unrelated
121 * protocol call later in the same transaction.
122 *
123 * @dev Zeroing `LEN_SLOT` is sufficient: every read path is gated on
124 * `len > 0` (`hasQueue`) or `head < len` (`popNext` / `discardNext`),
125 * so a zero length makes the queue effectively absent. We also reset
126 * `HEAD_SLOT` for a clean slate — costs one extra `tstore` and keeps
127 * a follow-up `loadQueue` call in this same tx from inheriting a
128 * stale head pointer. Per-entry word slots are not cleared; they are
129 * unreachable while `len == 0` and a future `loadQueue` overwrites
130 * them as needed.
131 */
132function clearQueue() internal {
133 bytes32 lenSlot = LEN_SLOT;
134 bytes32 headSlot = HEAD_SLOT;
135 assembly {
136 tstore(lenSlot, 0)
137 tstore(headSlot, 0)
138 }
139}

Recommendation:

We advise a modifier to be introduced instead that loads the queue at the beginning and clears it at the end, reducing the possibility of misuse by integrators of the library.

Alleviation (8fccc2716047809e4bc7786c95d346e5c61b2896):

A new TokenTransferAuthorizationBase contract was introduced that exposes a modifier via its TokenTransferAuthorizationBase::withTokenAuthorization signature, implementing the ease-of-use modifier as we advised.