Transfers
Operations → Transfers (Composer and Call Forwarder)
Lead type: ComposerCommands.TRANSFERS
.
The sub types are defined by the following enum:
TransferIds
Enum
Value | Name | Description |
---|---|---|
0 | TRANSFER_FROM |
Pull funds from caller |
1 | SWEEP |
Send funds from this contract |
3 | UNWRAP_WNATIVE |
Unwrap native currency |
4 | PERMIT2_TRANSFER_FROM |
Permit2 transfer |
5 | APPROVE |
Approve target |
SweepType Enum
Value | Name | Description |
---|---|---|
0 | VALIDATE |
Check if balanceOf(address(this)) >= amount , if true transfer it, if not revert |
1 | AMOUNT |
Transfer the amount without validation |
To encode an operation, the caller has to append
abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.[Operation]),
...params
);
to the array of composer commands.
Transfer From Operation
Pull funds from the caller to a receiver address.
Parameters
Offset | Length (bytes) | Description |
---|---|---|
0 | 20 | asset address |
20 | 20 | receiver address |
40 | 16 | amount uint128 |
Notes
If amount
is 0
, we pull asset.balanceOf(caller)
.
Encoding Example
// Solidity
bytes memory transferFromOp = abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.TRANSFER_FROM),
assetAddress,
receiverAddress,
uint128(amount)
);
// TypeScript
const transferFromOp = encodePacked(
["uint8", "uint8", "address", "address", "uint128"],
[TRANSFERS_COMMAND, TransferIds.TRANSFER_FROM, assetAddress, receiverAddress, amount]
)
Sweep Operation
Pull funds from this contract to a provided address.
Parameters
Offset | Length (bytes) | Description |
---|---|---|
0 | 20 | asset address |
20 | 20 | receiver address |
40 | 1 | sweepType SweepType |
41 | 16 | amount uint128 |
Enums Used
- SweepType Enum - Validation mode for the sweep operation
Notes
Note that asset
can be the zero address for native currency.
Encoding Examples
// Solidity - Basic sweep
bytes memory sweepOp = abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.SWEEP),
assetAddress,
receiverAddress,
uint8(SweepType.AMOUNT),
uint128(amount)
);
// TypeScript - Basic sweep
const sweepOp = encodePacked(
["uint8", "uint8", "address", "address", "uint8", "uint128"],
[TRANSFERS_COMMAND, TransferIds.SWEEP, assetAddress, receiverAddress, SweepType.AMOUNT, amount]
)
Sweeping Full Balance
To sweep the entire balance of an asset without knowing the exact amount, set amount = 0
and use SweepType.VALIDATE
:
// Sweep entire token balance
function encodeSweepFullBalance(asset: string, receiver: string) {
return abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.SWEEP),
asset,
receiver,
uint8(SweepType.VALIDATE), // fetch actual balance and validate
uint128(0) // amount = 0 triggers balanceOf lookup
)
}
This works because:
SweepType.VALIDATE
fetches the actual balance usingbalanceOf(address(this))
amount = 0
ensures the validation always passes (balance >= 0)- The full balance is transferred to the receiver
Important: if the balance is zero and
amount = 0
, the validation passes and the contract skips the empty transfer execution - this is ideal for refunding dust.
Wrapping Native Currency
To wrap
the native currency to wrapped native, you can just use asset=address(0),receiver=wrappedNativeAddress
.
// Wrap native currency using SWEEP operation
function encodeWrap(amount: bigint, wrapTarget: string) {
return abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.SWEEP),
address(0), // signals native asset
wrapTarget, // wrapped native contract address
uint8(SweepType.AMOUNT),
uint128(amount)
)
}
This works because:
asset = address(0)
tells the system to handle native currency- The wrapped native contract's
receive()
orfallback()
function automatically wraps incoming native currency
Unwrap WNative Operation
Unwrap native asset and transfer if needed.
Parameters
Offset | Length (bytes) | Description |
---|---|---|
0 | 20 | wrappedNativeAddress address |
20 | 20 | receiver address |
40 | 1 | sweepType SweepType |
41 | 16 | amount uint128 |
Enums Used
- SweepType Enum - Validation mode for the unwrap operation
Notes
Note that we do not hard-code the wrapped native address as some chains have duplicate wnative implementations.
Encoding Example
// Solidity
bytes memory unwrapOp = abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.UNWRAP_WNATIVE),
wrappedNativeAddress,
receiverAddress,
uint8(SweepType.AMOUNT),
uint128(amount)
);
// TypeScript
const unwrapOp = encodePacked(
["uint8", "uint8", "address", "address", "uint8", "uint128"],
[TRANSFERS_COMMAND, TransferIds.UNWRAP_WNATIVE, wrappedNativeAddress, receiverAddress, SweepType.AMOUNT, amount]
)
Permit2 Transfer From Operation
Execute a transfer via permit2. We only support the canonical Uniswap permit2 at address 0x000000000022D473030F116dDEE9F6B43aC78BA3
.
Parameters
Offset | Length (bytes) | Description |
---|---|---|
0 | 20 | asset address |
20 | 20 | receiver address |
40 | 16 | amount uint128 |
Notes
If amount
is 0
, we pull asset.balanceOf(caller)
.
Encoding Example
// Solidity
bytes memory permit2TransferOp = abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.PERMIT2_TRANSFER_FROM),
assetAddress,
receiverAddress,
uint128(amount)
);
// TypeScript
const permit2TransferOp = encodePacked(
["uint8", "uint8", "address", "address", "uint128"],
[TRANSFERS_COMMAND, TransferIds.PERMIT2_TRANSFER_FROM, assetAddress, receiverAddress, amount]
)
Approve Operation
Approve an asset - typically for a lender operation or external call.
Parameters
Offset | Length (bytes) | Description |
---|---|---|
0 | 20 | token address |
20 | 20 | target address |
Notes
ERC20-Approve the target
via token
, always uses infinite approve, the approval is stored and skipped if already done in the past.
Encoding Example
// Solidity
bytes memory approveOp = abi.encodePacked(
uint8(ComposerCommands.TRANSFERS),
uint8(TransferIds.APPROVE),
tokenAddress,
targetAddress
);
// TypeScript
const approveOp = encodePacked(["uint8", "uint8", "address", "address"], [TRANSFERS_COMMAND, TransferIds.APPROVE, tokenAddress, targetAddress])