Author: Florin Avram, @florin (Forum), Markus Laeng, @m.laeng, youves contributors
First publication date: 2023/08/11
Summary
In 2021-12-14 the youves community decided on the legacy YIP-002 to introduce a new synthetic asset which shall track the value of gold and be called uXAU. Back at the time community just had launched uDEFI and realised that without the ability to concentrate the liquidity at a specific target price, the synthetic asset would track only with conversion events involved (i.e. conversion options or liquidations). As there was no obvious solution to this challenge the decision was taken to only launch uXAU once a solution would be found. Meanwhile the research team at ubinetic found a solution to solve the liquidity at target problem built on top of the flat curves already used on the platform.
This proposal aims at expanding the Youves protocol with a new synthetic asset uXAU which will track the value of gold. For the community this means that a new engine will be deployed (we start with uXAU engine with USDT collateral) that allows users minting of uXAU tokens. Furthermore a modified flat curve swap which concentrates the liquidity at target is also part of this proposal. The price of Gold is provided by the Acurast on-chain oracle and observes for now these sources:
A second change we would like to bring to the DAO is to reduce the waiting time between a proposal being submitted and allowing our users to vote. Currently the waiting period is 11520 blocks (roughly 2 days) and we would like to reduce this period to 12 hours or less (depending on the response we get from our community). This reduces the waiting period, but still allows users to verify the proposal and if they find something they disagree with can still change their vote as our DAO implementation allows it.
At last we would like to fix a minor issue introduced in the previous YIP, by correctly updating the options contract of the uXTZ engines.
Rationale
Gold is an asset that it is underlooked in the Tezos ecosystem. By creating a synthetic asset that tracks gold we allow our users more ways in which they can use the platform and moreover we can foresee that the token will be adopted by other platforms, further increasing activity in the Tezos ecosystem.
Motivation
As stated above, we would like to be early adopters of a gold tracking synthetic asset. Moreover our community has expressed their interest in such an asset.
Caveats/Limitations
The Gold market (XAU/USD) operates within the conditions of “traditional finance” and mirrors the behaviour of a foreign exchange market. As a result, obtaining price feeds for gold during weekends and public holidays becomes unattainable. This behaviour poses a challenge for certain actions involving uXAU that rely on oracle price feeds for execution, as these actions are rendered impossible during non-forex trading hours.
Due to this limitations certain operations will not be allowed in either the uXAU engine or the uXAU - uUSD swap. These operations are the following:
- minting uXAU
- swaping either uXAU to uUSD or uUSD to uXAU
- step-ins/liquidations
- options fulfillment
Methodology
In the following section we will present the steps needed to create the new synthetic asset, engine and swap step by step.
-
Step 1 - Deploy a new uXAU - uUSD yielding flat curve swap. The flat curve will assume that the uXAU asset will have token id 4 in our synthetic assets contract. Until the proposal is executed this flat curve swap will be unusable. With a 0.35% fee split among the liquidity providers and the unified staking pool.
Added on 2023-08-12: This uXAU - uUSD flat curve pool has already been deployed and tested on ghostnet (KT1DRoTPmuC5dkNwi15bb3jCA3K1LPixgEdq) and has already been deployed on mainnet (KT1Ad5yJzoiRRdMJPvhJiPJ7Cq8WbJnCS7bg).
The code for the uXAU - uUSD flat curve pool is published on the youves GitHub. -
Step 2 - Deploy a new uXAU engine with USDT collateral. Same as with the flat curve, the engine assumes that uXAU asset will have token id 4 in our synthetic assets contract.
Added on 2023-08-12: This new engine has already been deployed and tested on ghostnet (KT1SYK5UnacFrVmoAcWoat69HtjAnRwt9tyc) and has already been deployed on mainnet (KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA). The code used is the same as for all token collateralized v3 engines, which is published on the youves GitHub.
Until the proposal is executed the engine is not wired in the Youves protocol, therefore it will be unusable.
The newly created engine will have the following parameters:- collateral ratio: 110%
- introducer ratio: 10%
- liquidation payout ratio: 6.25% liquidation reward
- minting fee: 0.3125%
- settlement payout ratio: 6.25% settlement premium
- settlement ratio: 115%
- settlement reward fee ratio: 10%
- spread rate: 1% yearly
- reference interest rate: 5.564109 %
-
Step 3 - Our team will develop the lambda for the proposal. The lambda will:
- create the uXAU asset with token id 4 in our synthetic assets contract
- wire the new uXAU engine with USDT collateral in the Youves protocol
- reduce the waiting period between proposal submission and start voting for future proposals to a value agreed by the community
- address the options contract for the uXTZ engines.
-
Step 4 - The community can review the flat curve swap, engine and lambda of the proposal
-
Step 5 - The lambda will be submitted to the DAO.
Proposal
The following section explains the content of the lambda that will be executed if YIP-2 is accepted by YOU stakers:
Change 1 - Add uXAU as a new synthetic asset token with token id 4
The lambda will create the uXAU assets that will have token id 4 in our synthetic assets contract KT1XRPEPXbZK25r3Htzp2o1x7xdMMmfocKNW
.
Change 2 - Wire a new uXAU engine with USDT collateral in the youves protocol
The lambda will wire in the uXAU engine with USDT collateral in the youves protocol by doing the following operations:
- setting the new engine
KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA
as an admin for the uXAU synthetic asset - set the uXAU engine as an admin for the stake manager
KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4
- set the staking factor for the uXAU engine in the stake manager
- set the uXAU - uUSD swap
KT1Ad5yJzoiRRdMJPvhJiPJ7Cq8WbJnCS7bg
as the interest payments receiver.
After these changes the engine will be wired in the Youves protocol and users will be able to mint new uXAU synthetic assets or use it in any way they see fit. The engine will function like any other Youves engine, but having the limitations presented above.
Change 3 - Reduce the waiting period between proposal submission and voting period
The lambda will reduce the waiting period from 2 days to an agreed period of time. After this change the users will be able to vote faster for future proposals.
Change 4 - Update the options contract for uXTZ engines
The lambda will do the following changes:
- Set
KT1GL6CBm93edDHogUVQzasUd6m7384eZk3J
as the options contract for the uXTZ/XTZ engineKT1Mf9Nr1KyGC6gUz9pGQnngzWbbZ6thShvc
- Set
KT1CHL9XVrt3Avr1mHkCiZBANEeJzbUSGqGB
as the options contract for the uXTZ/SIRS engineKT1ByNrcyDxYLmamuJbeFJukYkLJaZ1W86Yr
After these changes the options will be enabled in the uXTZ/XTZ and uXTZ/SIRS engines.
Code
Source code in SmartPy (or any other language used)
This is the SmartPy source code of the lambda which will be executed with this proposal, YIP-2:
Also published on Github here.
import smartpy as sp
def execute_set_token_metadata(token_address, token_id, token_info):
token_contract = sp.contract(
sp.TPair(sp.TNat, sp.TMap(sp.TString, sp.TBytes)),
token_address,
entry_point="set_token_metadata",
).open_some()
payload = sp.pair(token_id, token_info)
return sp.transfer_operation(payload, sp.mutez(0), token_contract)
def set_uxau_token_metadata(unit):
sp.set_type(unit, sp.TUnit)
sp.result(
sp.list([
execute_set_token_metadata(
sp.address("KT1XRPEPXbZK25r3Htzp2o1x7xdMMmfocKNW"),
sp.nat(4),
sp.map(
l={ "" : sp.bytes("0x697066733a2f2f516d553972507434354b51466d35315a46467a65727a6231586645726f7a6d31734d4678443478705851394e526e")},
tkey=sp.TString,
tvalue = sp.TBytes
)
)
])
)
def execute_execute(administrable_address, executable_lambda):
administrable_contract = sp.contract(
sp.TLambda(sp.TUnit, sp.TList(sp.TOperation)),
administrable_address,
entry_point="execute",
).open_some()
return sp.transfer_operation(
sp.build_lambda(executable_lambda), sp.mutez(0), administrable_contract
)
def execute_add_administrator(administrable_address, new_admin, token_id):
administrable_contract = sp.contract(
sp.TPair(sp.TAddress, sp.TNat),
administrable_address,
entry_point="set_administrator",
).open_some()
payload = sp.pair(new_admin, token_id)
return sp.transfer_operation(payload, sp.mutez(0), administrable_contract)
def add_administrator_to_contract(unit, administrable_address, admin_to_add, token_id):
sp.set_type(unit, sp.TUnit)
sp.result(
sp.list(
[execute_add_administrator(administrable_address, admin_to_add, token_id)]
)
)
def execute_set_stake_factor(administrable_address, address, factor):
administrable_contract = sp.contract(
sp.TPair(sp.TAddress, sp.TNat),
administrable_address,
entry_point="set_stake_factor",
).open_some()
payload = sp.pair(address, factor)
return sp.transfer_operation(payload, sp.mutez(0), administrable_contract)
def execute_set_contracts_engine_v3(
engine_address,
interest_rate_setter_contract,
options_contract,
governance_token_contract,
savings_pool_contract,
target_price_oracle,
reward_pool_contract,
):
engine_contract = sp.contract(
sp.TPair(
sp.TPair(sp.TAddress, sp.TPair(sp.TAddress, sp.TAddress)),
sp.TPair(sp.TAddress, sp.TPair(sp.TAddress, sp.TAddress)),
),
engine_address,
entry_point="set_contracts",
).open_some()
payload = sp.pair(
sp.pair(
governance_token_contract,
sp.pair(interest_rate_setter_contract, options_contract),
),
sp.pair(
reward_pool_contract, sp.pair(savings_pool_contract, target_price_oracle)
),
)
return sp.transfer_operation(payload, sp.mutez(0), engine_contract)
def DAO_YIP_02(unit):
sp.set_type(unit, sp.TUnit)
#############################
# DAO new governance params #
#############################
dao_entrypoint = sp.contract(
GOVERNANCE_PARAMS_TYPE,
sp.address('KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab'), # youves DAO
entry_point="set_governance_params"
).open_some(message='DAO: Invalid entry point set_governance_params')
# new governance params for DAO
new_governance_params = sp.record(
escrow_amount = sp.nat(1_000_000_000_000_000), # 1000 YOUs
vote_delay_blocks = sp.nat(1440), # 6 hours
vote_length_blocks = sp.nat(28800), # 5 days (remains the same)
min_yes_votes_percentage_for_escrow_return = sp.nat(30), # 30% (remains unchanged)
timelock_execution_delay_blocks = sp.nat(11520), # 2 days (remains unchanged)
timelock_cancelation_delay_blocks = sp.nat(23040), # 4 days (remains unchanged)
super_majority_percentage = sp.nat(80), # 80% (remains unchanged)
quorum_cap = sp.record(
lower = sp.nat(800_000_000_000_000_000), # 0.8M (remains unchanged)
upper = sp.nat(3_744_000_000_000_000_000) # 3.744M (remains unchanged)
),
)
sp.set_type_expr(new_governance_params, GOVERNANCE_PARAMS_TYPE)
# DAO LAMBDA
sp.result(sp.list([
execute_execute(sp.address("KT1FFE2LC5JpVakVjHm5mM36QVp2p3ZzH4hH"), set_uxau_token_metadata), # add uXAU token to the synthetic contract
execute_execute(
sp.address("KT1FFE2LC5JpVakVjHm5mM36QVp2p3ZzH4hH"),
lambda unit: add_administrator_to_contract(
unit,
sp.address("KT1XRPEPXbZK25r3Htzp2o1x7xdMMmfocKNW"),
sp.address('KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA'),
sp.nat(4)
)
), # add the uXAU engine as admin to the uXAU token
execute_add_administrator(sp.address("KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4"), sp.address('KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA'), 0), # add the uXAU engine as admin to the stake manager
# for the price 1oz gold = 1931.16 usd and 1 tez = 0.791470 usd the stake factor is 2439.96613896 * 10^18.
execute_set_stake_factor(sp.address("KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4"), sp.address('KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA'), 2_439_966_138_960_000_000_000), # set the stake factor of the uXAU token.
sp.transfer_operation(new_governance_params, sp.mutez(0), dao_entrypoint),
execute_set_contracts_engine_v3(
sp.address('KT1Mf9Nr1KyGC6gUz9pGQnngzWbbZ6thShvc'), # uXTZ/XTZ collateral engine
sp.address('KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab'), # youves DAO as interest rate setter (remains the same)
sp.address('KT1GL6CBm93edDHogUVQzasUd6m7384eZk3J'), # options contract
sp.address('KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4'), # stake manager (remains the same)
sp.address('KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS'), # savings_pool (remains the same)
sp.address('KT1PuCU5UAoaX2Hjcns2SEmJWBC34tfLjzaS'), # target price oracle (remains the same)
sp.address('KT1KXvsh7vnPUkBj1oG1E3LUoFnKHsf7Wixo'), # unified staking proxy as rewards receiver (remains the same)
),
execute_set_contracts_engine_v3(
sp.address('KT1ByNrcyDxYLmamuJbeFJukYkLJaZ1W86Yr'), # uXTZ/SIRS collateral engine
sp.address('KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab'), # youves DAO as interest rate setter (remains the same)
sp.address('KT1CHL9XVrt3Avr1mHkCiZBANEeJzbUSGqGB'), # options contract
sp.address('KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4'), # stake manager (remains the same)
sp.address('KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS'), # savings_pool (remains the same)
sp.address('KT1TSwSAU1qUyRFYBv6ix5YzqLBparxJ3FAk'), # target price oracle (remains the same)
sp.address('KT1KXvsh7vnPUkBj1oG1E3LUoFnKHsf7Wixo'), # unified staking proxy as rewards receiver (remains the same)
),
]))
Compiled Michelson code
This is the compiled Michelson code of the above SmartPy code.
Also published on Github here.
{ NIL operation; PUSH address "KT1ByNrcyDxYLmamuJbeFJukYkLJaZ1W86Yr"; CONTRACT %set_contracts (pair (pair address (pair address address)) (pair address (pair address address))); IF_NONE { PUSH int 176; FAILWITH } {}; PUSH mutez 0; PUSH (pair (pair address (pair address address)) (pair address (pair address address))) (Pair (Pair "KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4" (Pair "KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab" "KT1CHL9XVrt3Avr1mHkCiZBANEeJzbUSGqGB")) (Pair "KT1KXvsh7vnPUkBj1oG1E3LUoFnKHsf7Wixo" (Pair "KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS" "KT1TSwSAU1qUyRFYBv6ix5YzqLBparxJ3FAk"))); TRANSFER_TOKENS; CONS; PUSH address "KT1Mf9Nr1KyGC6gUz9pGQnngzWbbZ6thShvc"; CONTRACT %set_contracts (pair (pair address (pair address address)) (pair address (pair address address))); IF_NONE { PUSH int 176; FAILWITH } {}; PUSH mutez 0; PUSH (pair (pair address (pair address address)) (pair address (pair address address))) (Pair (Pair "KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4" (Pair "KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab" "KT1GL6CBm93edDHogUVQzasUd6m7384eZk3J")) (Pair "KT1KXvsh7vnPUkBj1oG1E3LUoFnKHsf7Wixo" (Pair "KT1BFXgczFte2zftCTg7tL6Qk2capsFg6UFS" "KT1PuCU5UAoaX2Hjcns2SEmJWBC34tfLjzaS"))); TRANSFER_TOKENS; CONS; PUSH address "KT1C3T98TqCm38cHPauZ4SopkQ4torCsxgab"; CONTRACT %set_governance_params (pair (nat %escrow_amount) (pair (nat %vote_delay_blocks) (pair (nat %vote_length_blocks) (pair (nat %min_yes_votes_percentage_for_escrow_return) (pair (nat %timelock_execution_delay_blocks) (pair (nat %timelock_cancelation_delay_blocks) (pair (nat %super_majority_percentage) (pair %quorum_cap (nat %lower) (nat %upper))))))))); IF_NONE { PUSH string "DAO: Invalid entry point set_governance_params"; FAILWITH } {}; PUSH mutez 0; PUSH (pair nat nat) (Pair 800000000000000000 3744000000000000000); PUSH nat 80; PUSH nat 23040; PUSH nat 11520; PUSH nat 30; PUSH nat 28800; PUSH nat 1440; PUSH nat 1000000000000000; PAIR 8; DIG 4; DROP; TRANSFER_TOKENS; CONS; PUSH address "KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4"; CONTRACT %set_stake_factor (pair address nat); IF_NONE { PUSH int 276; FAILWITH } {}; PUSH mutez 0; PUSH (pair address nat) (Pair "KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA" 2439966138960000000000); TRANSFER_TOKENS; CONS; PUSH address "KT1Ge5usHwAAH12PDxwP8FFYMdbMbXSRXSz4"; CONTRACT %set_administrator (pair address nat); IF_NONE { PUSH int 212; FAILWITH } {}; PUSH mutez 0; PUSH (pair address nat) (Pair "KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA" 0); TRANSFER_TOKENS; CONS; PUSH address "KT1FFE2LC5JpVakVjHm5mM36QVp2p3ZzH4hH"; CONTRACT %execute (lambda unit (list operation)); IF_NONE { PUSH int 266; FAILWITH } {}; PUSH mutez 0; LAMBDA unit (list operation) { DROP; NIL operation; PUSH address "KT1XRPEPXbZK25r3Htzp2o1x7xdMMmfocKNW"; CONTRACT %set_administrator (pair address nat); IF_NONE { PUSH int 212; FAILWITH } {}; PUSH mutez 0; PUSH (pair address nat) (Pair "KT1VhU47n633rqJeAZESfbejnxeJmpXVx3AA" 4); TRANSFER_TOKENS; CONS }; TRANSFER_TOKENS; CONS; PUSH address "KT1FFE2LC5JpVakVjHm5mM36QVp2p3ZzH4hH"; CONTRACT %execute (lambda unit (list operation)); IF_NONE { PUSH int 266; FAILWITH } {}; PUSH mutez 0; LAMBDA unit (list operation) { DROP; NIL operation; PUSH address "KT1XRPEPXbZK25r3Htzp2o1x7xdMMmfocKNW"; CONTRACT %set_token_metadata (pair nat (map string bytes)); IF_NONE { PUSH int 257; FAILWITH } {}; PUSH mutez 0; PUSH (pair nat (map string bytes)) (Pair 4 {Elt "" 0x697066733a2f2f516d553972507434354b51466d35315a46467a65727a6231586645726f7a6d31734d4678443478705851394e526e}); TRANSFER_TOKENS; CONS }; TRANSFER_TOKENS; CONS }
SHA256 Hash of the Michelson code
SHA256 Hash of the above Michelson code:
7d7222b6a7dcc17ef7e629f13665796e6cc790b2c98f2c8cd0df4a5c4d288bbd
Edits:
2023-08-14: Added Markus as autor, added contract addresses of the deployed uXAU ghostnet engine and ghostnet swap contract, added contract addresses of the deployed uXAU mainnet engine and mainnet swap.