Execute() for Chaining & Complex Operations

Execute(), one function to do all the SWAP/LPing/Vote/Stake/bribe/etc.

  • ISwap refers to pools supporting this opertaion

  • For CPMM(Volatile pools) and Wombat pools, LP deposit/withdrawal can be performed by 'buying/selling' LP tokens from/to underlying tokens.

    • This is an important concept. Adding/removing liquidity is not a separate function, it's the act of swapping tokens for LP tokens!

  • VC and veVC are ISwap; VC can be 'bought' with old VC; and veVC can be bought with old veNFTs or new VC. ( This was only used in zkSync in the past, migrating from v1 to v2, and is now obsolete )

  • the plan is to make veVC act as the liquidity pool for veVC; this is not implemented yet.

Stake diverges from swap as the Vault calculates and emits VC before operation. It is used for interacting with gauges.

  • IGauge refers to pools supporting this opertaion

  • CPMM is both ISwap and IGauge.

  • Wombat pools have multiple gauges; one for each lp token.

  • Harvesting can usually be performed by specifying [VC, at most, 0], without any lp tokens.

Convert involves actual token transfer, different from swap. The Vault transfers desiredAmount to the pool before calling the pool, and the pool sends the output to the vault.

  • IConverter refers to pools supporting this opertaion.

  • Vault only monitors specified tokens balance changes; any unspecified tokens received will be lost.

  • This is useful for converting tokens to/from wrapped tokens (e.g. WETH or rfUSDC) or for flash loans.

Vote is significantly different from swap. This operation requires the pool to be IGauge, and tokenInformation must include veVC and any bribe tokens user wants to receive. Like stake, it sends VC emission and calculates and sends any bribes attached to the gauge. To (un)vote, users must specify the desiredAmount of the veVC. Any bribes not included in tokenInformation will be credited to userBalance instead.

  • Harvesting can usually be performed by specifying [veVC, exactly, 0], along with bribe tokens.

userBalance:

userbalance is the user's token-specific balance held in the vault, unused, and available for withdrawal at any time, stored in userbalance[useraddress][Token]. pro traders can save gas by preloading their tokens into userBalance to avoid having to perform a token transfer every time they trade.

Pool in this operation can be any address, allowing depositing any tokens to any address. Withdrawal is only possible from your userBalance.

Vault.query()

function query(
    address user,
    Token[] memory tokenRef,
    int128[] memory deposit,
    VelocoreOperation[] calldata ops
) public returns (int128[] memory)

To determine the expected amounts received from transactions, use Vault.query(). The function parameters are the same as before, with the addition of user, which specifies the transaction maker. The function returns an array of int128 representing the final transactional changes in token balances.

Pseudocode Example

// helper functions

const toToken = (spec: string, id: BigNumber, addr: string) =>
	solidityPack(
		["uint8", "uint120", "address"],
		[["erc20", "erc721", "erc1155"].indexOf(spec), id, addr]
	)
const poolId = (poolAddress: string) =>
    solidityPack(
	    ["bytes1", "uint120", "address"],
	    ["0x00", 0, poolAddress]
    )

const tokenInformation = (index: number, amountType: string, amount: BigNumber) =>
	solidityPack(["uint8", "uint8", "uint112", "int128"], [
		index,
		["exactly", "at most", "all"].indexOf(amountType),
		0,
		amount
	]
)

const compileAndExecute = (ops) => {
	const tokenRef = [...new  Set(ops.map(x => x[1].map(i => i[0])))].sort();
	return vault.execute(
		tokenRef,
		(new  Array(tokenRef.length)).fill(0),
		ops.map(op => ({
			poolId: op[0]
			tokenInforamtions: op[1].map(i => tokenInformation(tokenRef.indexOf(i[0]), i[1], i[2])).sort(),
			data: []
		}))
	);
}


const usdc = toToken("erc20", 0, "0xUSDC");
const usdt = toToken("erc20", 0, "0xUSDT");
const eth = "0xEEE...EEE";

// actually make transactions
await compileAndExecute([
	[poolId("0x12311..."), [
		[usdc, "exactly", 1234],
		[usdt, "at most", 0]
	]],
	[poolId("0x1ab3234..."), [
		[usdt, "all", INT128_MAX],
		[eth, "at most", -1234],
	]]
])

Last updated