Skip to content

Commit

Permalink
Implement deposit/withdraw/redeem (minus contract calls). Add set_uma…
Browse files Browse the repository at this point in the history
…_address/set_balancer_address/set_swaps_completed ajax calls. Assign price identifier (with model). Store abis as hidden fields, so that contracts can load the token contracts and approve transfers. Add :net_collateral_adjustment to uma_snapshot to enable deposit/withdraw/redeem. Add finalized flag to BalancerPool, and finalized button. Move UMA_COLLATERALIZATION from Pie model to initializer. Add implementations of blockchain token swap and balancer creation. Add amount_to_receive (for Uniswap exact in). Post processes in BalanceCalculator to adjust for Synthetic collateralization and extra ETH to aETH swap, if ETH is a crypto (since Balancer can only hold ERC-20 tokens). Add Utilities.current_timestamp, and fix the toHex method to return a valid Bytes32 (has to be 0x + 64 bytes).
  • Loading branch information
EndymionJkb committed May 21, 2020
1 parent b6f7646 commit a52194c
Show file tree
Hide file tree
Showing 23 changed files with 631 additions and 106 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
!/log/.keep
!/tmp/.keep
db/data/ExpiringMultiPartyCreator.txt
db/data/TokenFactory.txt

# Ignore uploaded files in development
/storage/*
!/storage/.keep
Expand Down
54 changes: 54 additions & 0 deletions app/assets/javascripts/uma_synthetic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
function deposit_collateral(pie) {
var amount = $('#amount').val();

if (amount > 0) {
jQuery.ajax({url: '/pies/'+ pie + '/deposit_collateral.js',
data: {'amount': amount},
type: "PUT",
success: function(data) { update_graphics(JSON.parse(data)); },
error: function() { alert('Oh noes!'); },
async: false});
}
else {
alert("Please enter a valid amount");
}
}

function withdraw_collateral(pie) {
var amount = $('#amount').val();

if (amount > 0) {
jQuery.ajax({url: '/pies/'+ pie + '/withdraw_collateral.js',
data: {'amount': amount},
type: "PUT",
success: function(data) { update_graphics(JSON.parse(data)); },
error: function() { alert('You cannot withdraw so much that your collateralization falls below the minimum!'); },
async: false});
}
else {
alert("Please enter a valid amount");
}
}

function redeem_tokens(pie) {
var amount = $('#amount').val();

if (amount > 0) {
jQuery.ajax({url: '/pies/'+ pie + '/redeem_tokens.js',
data: {'amount': amount},
type: "PUT",
success: function(data) { update_graphics(JSON.parse(data)); },
error: function() { alert('Oh noes!'); },
async: false});
}
else {
alert("Please enter a valid amount");
}
}

function update_graphics(data) {
$('#collateralization').text(data.collateralization);
$('#collateral_progress').attr('class', data.progress_class + " progress-bar progress-bar-striped");
$('#adjustments').text(data.adjustments);
$('#total_value').text(data.total_value);
}
122 changes: 86 additions & 36 deletions app/controllers/balancer_pools_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,40 @@ def update

redirect_to edit_balancer_pool_path(@pool)
end

def set_uma_address
@pool = BalancerPool.find(params[:id])

@pool.update_attribute(:uma_address, params[:uma_address])

respond_to do |format|
format.js { head :ok }
format.html { redirect_to root_path }
end
end

def set_balancer_address
@pool = BalancerPool.find(params[:id])

@pool.update_attribute(:bp_address, params[:bp_address])

respond_to do |format|
format.js { head :ok }
format.html { redirect_to root_path }
end
end

def set_swaps_completed
@pool = BalancerPool.find(params[:id])

@pool.update_attribute(:swaps_completed, true)

respond_to do |format|
format.js { head :ok }
format.html { redirect_to root_path }
end
end

def update_balances
@pool = BalancerPool.find(params[:id])
@alloc = YAML::load(@pool.allocation)
Expand Down Expand Up @@ -171,18 +204,44 @@ def show

# Read the address of the ExpiringMultiPartyCreator (from the uma_prep script)
@empCreatorAddress = IO.read('db/data/ExpiringMultiPartyCreator.txt')
@tokenFactoryAddress = IO.read('db/data/TokenFactory.txt')

@expiry_date_str = UmaExpiryDate.find_by_unix(@pie.uma_expiry_date).date_str
@uma_collateral_address = CoinInfo.find_by_coin(@pie.uma_collateral).address rescue nil
@uma_collateral = CoinInfo.find_by_coin(@pie.uma_collateral)

if @pie.price_identifier.nil?
# need to assign it
pi = PriceIdentifier.where(:pie_id => nil).first
if pi.nil?
raise 'No available price feed identifiers!'
else
@pie.update_attribute(:price_identifier, pi.id)
end
end

# Need to convert to Hex for contract
@price_feed_identifer = Utilities.utf8ToHex(@pie.price_identifier.whitelisted)

@data = YAML::load(@pool.allocation)
@client_address = @data[:address]
@abis = Hash.new

# Lots of processing to get the swaps, so do that in the controller
if @data.has_key?(:encoding) and @data[:encoding].has_key?(:transforms)
if @data[:encoding] and @data[:encoding][:transforms]
@transforms = []
@data[:encoding][:transforms].each do |t|
tx = {:method => 'AAVE' == t[:method] ? 'aave.svg' : 'uniswap.png'}
tx[:src] = CoinInfo.find_by_address(t[:src_coin]).coin
tx[:dest] = CoinInfo.find_by_address(t[:dest_coin]).coin
tx[:amount] = t[:num_tokens]
tx = {:method => t[:method], :image => 'AAVE' == t[:method] ? 'aave.svg' : 'uniswap.png'}
src_coin = CoinInfo.find_by_address(t[:src_coin])
dest_coin = CoinInfo.find_by_address(t[:dest_coin])
tx[:src] = src_coin.coin
tx[:src_addr] = src_coin.address
# Write as hidden fields in the UI
@abis[src_coin.coin] = src_coin.abi
tx[:dest] = dest_coin.coin
tx[:dest_addr] = dest_coin.address
tx[:num_tokens] = t[:num_tokens]
tx[:amount] = t[:amount]
tx[:amount_to_receive] = t[:amount_to_receive]

@transforms.push(tx)
end
Expand All @@ -191,28 +250,33 @@ def show
end

@pool_config = []
@data[:encoding][:pool].each do |p|
pc = Hash.new
pc[:coin] = CoinInfo.find_by_address(p[:coin]).coin
pc[:amount] = p[:num_tokens]
pc[:weight] = (p[:weight] * 100.0).round(1)
pc[:denorm] = (p[:weight] * 50).round(1)

@pool_config.push(pc)
if @data[:encoding]
@data[:encoding][:pool].each do |p|
pc = Hash.new
info = CoinInfo.find_by_address(p[:coin])
pc[:coin] = info.coin
@abis[info.coin] = info.abi
pc[:coin_addr] = info.address
pc[:amount] = p[:num_tokens]
pc[:amount_wei] = p[:amount]
pc[:weight] = (p[:weight] * 100.0).round(1)
pc[:denorm] = (p[:weight] * 50).round(2)

@pool_config.push(pc)
end
end

if @pool.uma_address.nil?
@synthetic = nil
else
syn_data = YAML::load(@pie.uma_snapshot)
@synthetic = {:investment => syn_data[:investment], :slices => Hash.new}
@total_value = 0
@synthetic = {:investment => syn_data[:investment], :slices => Hash.new,
:net_collateral_adjustment => syn_data[:net_collateral_adjustment]}

@pie.etfs.each do |etf|
data = syn_data[:slices][etf.ticker]
current_price = etf.current_price
performance = (current_price - data[:price])/data[:price] * 100
@total_value += data[:shares] * current_price

@synthetic[:slices][etf.ticker] = {:basis => data[:price],
:shares => data[:shares],
Expand All @@ -224,17 +288,14 @@ def show
data = syn_data[:slices][stock.cca_id]
current_price = stock.current_price
performance = (current_price - data[:price])/data[:price] * 100
@total_value += data[:shares] * current_price

@synthetic[:slices][stock.company_name] = {:basis => data[:price],
:shares => data[:shares],
:price => current_price,
:performance => performance}
end

@collateralization = @total_value / syn_data[:investment] * 100

@progress_class = get_progress_class(@collateralization)
@collateralization, @progress_class, @total_value = @pie.compute_uma_collateralization
end
end

Expand All @@ -261,11 +322,12 @@ def index
total_value += data[:shares] * current_price
end

collateralization = total_value / syn_data[:investment] * 100
snap = YAML::load(pie.uma_snapshot)
collateralization, progress_class = pie.compute_uma_collateralization

current_syn[:current_value] = total_value
current_syn[:collateralization] = collateralization
current_syn[:progress_class] = get_progress_class(collateralization)
current_syn[:progress_class] = progress_class
current_syn[:price_identifier] = pie.price_identifier.whitelisted
current_syn[:uma_address] = pool.uma_address
current_syn[:token_symbol] = pie.uma_token_symbol
Expand Down Expand Up @@ -310,17 +372,5 @@ def sanity_check
unless @pool.user == current_user
redirect_to root_path, :alert => 'Wrong User'
end
end

def get_progress_class(collateralization)
if collateralization < Pie::UMA_COLLATERALIZATION * 100
progress_class = 'bg-danger'
elsif collateralization > (Pie::UMA_COLLATERALIZATION + 0.2) * 100
progress_class = 'bg-success'
else
progress_class = 'bg-warning'
end

progress_class
end
end
end
74 changes: 72 additions & 2 deletions app/controllers/pies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,83 @@ def copy

redirect_to edit_py_path(@pie), :notice => "Copied #{@src.name}"
end

def deposit_collateral
@pie = Pie.find(params[:id])

snap = YAML::load(@pie.uma_snapshot)

snap[:net_collateral_adjustment] += params[:amount].to_i
@pie.update_attribute(:uma_snapshot, YAML::dump(snap))

@collateralization, @progress_class, @total_value = @pie.compute_uma_collateralization

respond_to do |format|
format.js do
render :json => {:collateralization => @collateralization,
:progress_class => @progress_class,
:adjustments => snap[:net_collateral_adjustment],
:total_value => @total_value}
end
format.html { redirect_to root_path }
end
end

def synthetics_index
def withdraw_collateral
@pie = Pie.find(params[:id])

snap = YAML::load(@pie.uma_snapshot)

# They can't withdraw so much that the collateralization falls below the minimum!
snap[:net_collateral_adjustment] -= params[:amount].to_i
@collateralization, @progress_class, @total_value = @pie.compute_uma_collateralization(snap[:net_collateral_adjustment])

if @collateralization >= MIN_COLLATERALIZATION * 100
@pie.update_attribute(:uma_snapshot, YAML::dump(snap))
else
raise 'You cannot withdraw so much that the collateralization falls below the minimum!'
end

respond_to do |format|
format.js do
render :json => {:collateralization => @collateralization,
:progress_class => @progress_class,
:adjustments => snap[:net_collateral_adjustment],
:total_value => @total_value}
end
format.html { redirect_to root_path }
end
end

def balancer_index
# For a $500 investment, at a collateralization of 1.75, the intial deposit would be 875
# They would get 500 synthetic tokens for 875 Dai, for instance
# If they redeem 200 tokens, they should get back 200*1.75 = 350
# This only gets called if the redemption succeeds
def redeem_tokens
@pie = Pie.find(params[:id])

snap = YAML::load(@pie.uma_snapshot)

snap[:net_collateral_adjustment] += params[:amount].to_i * MIN_COLLATERALIZATION
@pie.update_attribute(:uma_snapshot, YAML::dump(snap))

@collateralization, @progress_class, @total_value = @pie.compute_uma_collateralization

respond_to do |format|
format.js do
render :json => {:collateralization => @collateralization,
:progress_class => @progress_class,
:adjustments => snap[:net_collateral_adjustment],
:total_value => @total_value}
end
format.html { redirect_to root_path }
end
end

def synthetics_index
end

def balancer_index
end

private
Expand Down
3 changes: 2 additions & 1 deletion app/models/balancer_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# created_at :datetime not null
# updated_at :datetime not null
# swaps_completed :boolean default(FALSE), not null
# finalized :boolean default(FALSE), not null
#
class BalancerPool < ApplicationRecord
belongs_to :pie
Expand All @@ -20,7 +21,7 @@ class BalancerPool < ApplicationRecord
INITIAL_INVESTMENT = 5000

validates_length_of :uma_address, :bp_address, :is => 42, :allow_nil => true
validates_inclusion_of :swaps_completed, :in => [true, false]
validates_inclusion_of :swaps_completed, :finalized, :in => [true, false]

def balancer_url
"https://pools.balancer.exchange/#/pool/#{self.bp_address}"
Expand Down
Loading

0 comments on commit a52194c

Please sign in to comment.