小数度を使用してボーナスを計算するためのイーサリアムスマート契約

画像






誰もが知っていることから始めます。 ICOはどこにでもあり、誰もがさまざまなプロジェクトを提供し、誰もがトークンを販売しています。 そして誰もが割引、ボーナス、条件などのある種の販売モデルを持っています。

奇妙なことに、このエリアは非常に実験的ですが、ボーナスモデルは非常に原始的です。 異なるボリュームまたは時間間隔とパーセンテージが存在するだけです。 そして、なぜそれを複雑にしますか? しかし、私はまだ試みます。 のための実験。 新しいものは常に惹きつけられます。



セキュリティの問題に加えて、スマートコントラクトを作成するときに2番目に重要な問題は、最適化の問題です。 各トランザクションはガスを消費するため、エーテルはトランザクション処理中に消費されます。 コードが複雑で、多くの計算が必要な場合、ICOの投資家にとって非常に高価になります。



ここで、投資した資金の量に応じて滑らかなボーナス曲線を作成したいと想像してください。 そして、単なる線形ではなく、べき乗則です。

ボーナス=(投資額^ 0.07)-1



チャートでは次のように表示されます。



画像



現在の統計によると、平均的な投資家は約5 ETHを投資しているため、ボリュームが1 ETH未満の場合、ボーナスは授与されないとします。



floatはまだ非常に実験的であり、非常に高価なので、uint型のみを使用して計算する必要があります。 この場合、乗算、除算、加算、減算のみを使用できます。



したがって、指数関数を連続して展開する必要があります。



a ^ x = e ^ xlnx = 1 + xlna +(xlna)^ 2/2!+(xlna)^ 3/3!+⋯−∞ <x <∞



次に、Xの対数を1回カウントし、異なる間隔で線形関数のセットで近似するためにいくつかのキーポイントを取得する必要があります。

次に、行の最初の4つのメンバーを例にとります。



次に、関数を呼び出すために通常の計算機と使用済みガスを使用して、エラーを評価します。

次のような結果になります。



たとえば、近似ln(1.07)の値を計算しました。



pragma solidity ^0.4.15; library SafeMath { function mul(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal constant returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint256 a, uint256 b) internal constant returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } contract Simple { using SafeMath for uint256; uint256 m100=100000000; uint256 ln3= 109861228; uint256 ln10=230258512; uint256 ln20=299573231; uint256 ln30=340119743; uint256 ln50=391202307; uint256 ln100=460517025; uint256 ln200=529831743; uint256 ln500=621460819; uint256 ln1000=690775527; function test2(uint256 a){ test1(a); } function test1(uint256 a) constant returns (uint256 result) { uint256 lnbase; uint256 a0; if(a > m100.mul(1000)){ lnbase = ln1000; a0 = a.div(1000); }else if(a > m100.mul(500)){ lnbase=ln500; a0 = a.div(500); }else if(a > m100.mul(200)){ lnbase = ln200; a0 = a.div(200); }else if(a > m100.mul(100)){ lnbase = ln100; a0 = a.div(100); }else if(a > m100.mul(50)){ lnbase = ln50; a0 = a.div(50); }else if(a > m100.mul(30)){ lnbase = ln30; a0 = a.div(30); }else if(a > m100.mul(20)){ lnbase = ln20; a0 = a.div(20); }else if(a > m100.mul(10)){ lnbase = ln10; a0 = a.div(10); }else if(a > m100.mul(3)){ lnbase = ln3; a0 = a.div(3); }else if(a > m100){ lnbase = 0; a0 = a; }else{ return a; } uint256 x=a0.sub(m100).mul(m100).div(a0.add(m100)); uint256 y=x.add(x.mul(x).mul(x)/m100/m100/3).mul(2); y=lnbase.add(y); y=y.mul(7)/100; x=a.add(a.mul(y)/m100); x = x.add(a.mul(y).mul(y)/m100/m100/2); y = a.mul(y).mul(y).mul(y); x = x.add(y/m100/m100/m100/6); return (x); } }
      
      





評価:



9 ETHに10 ^ 8を掛けて、関数に渡します。

900000000は1048494787、つまり 10.485 ETH(約16%のボーナス)

計算機で9 ^ 1.07 = 10.496378550818314120261545161046 ETH

エラー:0.001、つまり 0.1%



転送に費やされたトランザクションを考えると、このエラーはオンエアのコミッションと非常に匹敵します。 さらに精度が必要な場合は、シリーズの5つのメンバーを確実に追加できます。



この関数を呼び出すためのガス費用:

実行コスト9598ガス(コストは契約によって呼び出された場合にのみ適用されます)



1001 ETHの場合:

162102425800を1001 ^ 1.07 = 1623.54549(つまり、約62%のボーナス)と比較すると、精度は1.0015になります。 0.15%

実行コスト6406ガス(コストは契約によって呼び出された場合にのみ適用されます)



ご覧のように、現時点ではすべてのICOが200kのガスの使用を推奨していることを考慮すると、関数のガスコストはわずか(6〜9k)です。

同時に、平均的な取引の精度は手数料の範囲内です。



これが真空の馬のようなものであると思われる場合、 SINTEZプラットフォーム sintez.globalプロジェクトのボーナスシステムでは、計算に小数度と対数が使用されると言います。



All Articles