Skip to content

Commit 9eae657

Browse files
authored
Merge pull request ethereum#289 from nextyio/event
Events for stablecoin
2 parents 1f42c51 + 7e6476b commit 9eae657

15 files changed

+4287
-1769
lines changed

consensus/dccs/2_absorption.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import (
2020
"math"
2121
"math/big"
2222

23-
"github.com/ethereum/go-ethereum/accounts/abi/bind"
23+
"github.com/ethereum/go-ethereum/core/vm"
24+
25+
"github.com/ethereum/go-ethereum/core"
26+
"github.com/ethereum/go-ethereum/crypto"
27+
2428
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
2529
"github.com/ethereum/go-ethereum/common"
2630
"github.com/ethereum/go-ethereum/consensus"
@@ -35,11 +39,13 @@ import (
3539

3640
var (
3741
emptyHash = common.Hash{}
42+
43+
onBlockInitializedSignature = crypto.Keccak256([]byte("onBlockInitialized(uint256)"))[:4]
3844
)
3945

4046
// OnBlockInitialized handles supply absorption on each block initialization
41-
func OnBlockInitialized(chain consensus.ChainReader, header *types.Header, state *state.StateDB, medianPrice *Price) (types.Transactions, types.Receipts, error) {
42-
backend := backends.NewRealBackend(chain, header, state, nil) // consensus only
47+
func (c *Context) OnBlockInitialized(header *types.Header, state *state.StateDB, medianPrice *Price) (types.Transactions, types.Receipts, error) {
48+
backend := backends.NewRealBackend(c.chain, header, state, nil) // consensus only
4349
target := common.Big0
4450

4551
if medianPrice != nil {
@@ -71,42 +77,36 @@ func OnBlockInitialized(chain consensus.ChainReader, header *types.Header, state
7177

7278
log.Trace("VolatileToken supply before", "supply", supply)
7379

74-
seign, err := endurio.NewSeigniorage(params.SeigniorageAddress, backend)
75-
if err != nil {
76-
log.Error("Failed to create new Seigniorage contract executor", "err", err)
77-
return nil, nil, err
78-
}
80+
tx := types.NewTransaction(0, params.SeigniorageAddress, common.Big0, math.MaxUint64, common.Big0,
81+
append(onBlockInitializedSignature, common.BigToHash(target).Bytes()...))
7982

80-
consensusTransactOpts := &bind.TransactOpts{
81-
GasLimit: math.MaxUint64, // it's over 9000
82-
Signer: func(_ types.Signer, _ common.Address, tx *types.Transaction) (*types.Transaction, error) {
83-
return tx, nil
84-
},
85-
}
83+
gasPool := core.GasPool(math.MaxUint64)
84+
var gasUsed uint64
8685

87-
state.Prepare(emptyHash, emptyHash, 0)
86+
snap := state.Snapshot()
87+
88+
state.Prepare(tx.Hash(), emptyHash, 0)
89+
receipt, _, err := core.ApplyTransaction(c.chain.Config(), c.chain, &header.Coinbase, &gasPool, state, header, tx, &gasUsed,
90+
vm.Config{
91+
IgnoreNonce: true,
92+
Signer: types.ConsensusSigner{
93+
Address: params.ZeroAddress,
94+
}})
8895

89-
tx, err := seign.OnBlockInitialized(consensusTransactOpts, target)
9096
if err != nil {
97+
state.RevertToSnapshot(snap)
9198
log.Error("Failed to execute Seigniorage.OnBlockInitialized", "err", err)
9299
return nil, nil, err
93100
}
94-
failed := err != nil
95101

96-
newSupply, err := volatileToken.TotalSupply(nil)
102+
newSupply, _ := volatileToken.TotalSupply(nil)
97103
if newSupply.Cmp(supply) != 0 {
98104
log.Trace("VolatileToken supply after", "new supply", newSupply, "change", new(big.Int).Sub(newSupply, supply))
99105
stateObject := state.GetOrNewStateObject(params.VolatileTokenAddress)
100106
stateObject.SetBalance(newSupply)
101107
stateObject.CommitTrie(state.Database())
102108
}
103109

104-
root := state.IntermediateRoot(chain.Config().IsEIP158(header.Number)).Bytes()
105-
receipt := types.NewReceipt(root, failed, 0)
106-
receipt.Logs = state.GetLogs(emptyHash)
107-
// TODO: include failure log here
108-
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
109-
110110
return types.Transactions{tx}, types.Receipts{receipt}, nil
111111
}
112112

consensus/dccs/2_dccs.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,9 +544,12 @@ func (c *Context) initialize2(header *types.Header, state *state.StateDB) (types
544544
log.Trace("Failed to calculate canonical median price", "err", err, "number", header.Number)
545545
}
546546

547-
txs, receipts, err := OnBlockInitialized(c.chain, header, state, medianPrice)
547+
txs, receipts, err := c.OnBlockInitialized(header, state, medianPrice)
548+
if err != nil {
549+
return nil, nil, err
550+
}
548551
header.Root = state.IntermediateRoot(c.chain.Config().IsEIP158(header.Number))
549-
return txs, receipts, err
552+
return txs, receipts, nil
550553
}
551554

552555
// finalize2 implements consensus.Engine, ensuring no uncles are set, nor block

contracts/nexty/endurio/Seigniorage.go

Lines changed: 4059 additions & 1645 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/nexty/endurio/src/Absorbable.sol

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ contract Absorbable is Orderbook {
1313
using absn for absn.Absorption;
1414
using absn for absn.Preemptive;
1515

16+
event Absorption(int256 amount, uint256 supply, bool emptive);
17+
event Stop();
18+
event Slash(address maker, uint256 amount);
19+
event Unlock(address maker);
20+
1621
IToken VolatileToken;
1722
IToken StablizeToken; // spelling intented
1823

@@ -47,7 +52,8 @@ contract Absorbable is Orderbook {
4752
StablizeToken = IToken(stablizeToken);
4853
super.registerTokens(volatileToken, stablizeToken);
4954
// trigger the first blank absorption
50-
triggerAbsorption(StablizeToken.totalSupply(), false);
55+
uint supply = StablizeToken.totalSupply();
56+
triggerAbsorption(supply, supply, false, false);
5157
}
5258

5359
function toString(address x) internal pure returns (string memory) {
@@ -76,16 +82,17 @@ contract Absorbable is Orderbook {
7682
function onBlockInitialized(uint target) public consensus {
7783
if (last.isExpired()) {
7884
// absorption takes no longer than one duration
79-
delete last;
85+
stopAbsorption();
8086
}
8187
if (lockdown.unlockable()) {
8288
unlock();
8389
}
8490
uint supply = StablizeToken.totalSupply();
8591
if (target > 0) { // absorption block
86-
if (shouldTriggerPassive() ||
87-
shouldTriggerActive(supply, target)) {
88-
triggerAbsorption(target, false);
92+
if (shouldTriggerPassive()) {
93+
triggerAbsorption(target, supply, false, false);
94+
} else if (shouldTriggerActive(supply, target)) {
95+
triggerAbsorption(target, supply, true, false);
8996
}
9097
if (lockdown.isLocked()) {
9198
// WIP: slash the pre-emptive maker if target goes wrong way
@@ -163,14 +170,22 @@ contract Absorbable is Orderbook {
163170
if (lockdown.stake > 0) {
164171
VolatileToken.transfer(lockdown.maker, lockdown.stake);
165172
}
173+
emit Unlock(lockdown.maker);
166174
delete lockdown;
167175
}
168176

169-
function triggerAbsorption(uint target, bool isPreemptive) internal {
177+
function triggerAbsorption(uint target, uint supply, bool emptive, bool isPreemptive) internal {
170178
last = absn.Absorption(block.number + EXPIRATION,
171-
StablizeToken.totalSupply(),
179+
supply,
172180
target,
173181
isPreemptive);
182+
int amount = util.sub(target, supply);
183+
emit Absorption(amount, supply, emptive);
184+
}
185+
186+
function stopAbsorption() internal {
187+
delete last;
188+
emit Stop();
174189
}
175190

176191
function absorb(
@@ -213,11 +228,12 @@ contract Absorbable is Orderbook {
213228
if (lockdown.stake < slashed) {
214229
slashed = lockdown.stake;
215230
// there's nothing at stake anymore, clear the lockdown and its absorption
216-
delete last;
231+
stopAbsorption();
217232
unlock();
218233
}
219234
lockdown.stake -= slashed;
220235
VolatileToken.dexBurn(slashed);
236+
emit Slash(lockdown.maker, slashed);
221237
// this slashed NTY will be burnt by the consensus by calling setBalance
222238
return true;
223239
}

contracts/nexty/endurio/src/Preemptivable.sol

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ contract Preemptivable is Absorbable {
1414
using absn for absn.Proposal;
1515
using absn for absn.Preemptive;
1616

17+
event Revoke(address maker);
18+
event Propose(
19+
address maker,
20+
int256 amount,
21+
uint256 stake,
22+
uint256 lockdownExpiration,
23+
uint256 slashingDuration
24+
);
25+
event Preemptive(
26+
address maker,
27+
uint256 stake,
28+
uint256 lockdownExpiration,
29+
uint256 unlockNumber
30+
);
31+
1732
address constant ZERO_ADDRESS = address(0x0);
1833

1934
// adapting global default parameters, only used if proposal maker doesn't specify them
@@ -22,6 +37,7 @@ contract Preemptivable is Absorbable {
2237

2338
// adapting global requirement
2439
uint internal globalSuccessRank = 0;
40+
uint internal globalSuccessStake = 0;
2541

2642
// proposal params must not lower than 1/3 of global params
2743
uint constant PARAM_TOLERANCE = 3;
@@ -82,7 +98,7 @@ contract Preemptivable is Absorbable {
8298
// unused
8399
reserve = bytes32(0);
84100

85-
propose(maker, value, amount, slashingDuration, lockdownExpiration);
101+
propose(maker, amount, value, slashingDuration, lockdownExpiration);
86102
return;
87103
}
88104

@@ -116,24 +132,23 @@ contract Preemptivable is Absorbable {
116132
*/
117133
function propose(
118134
address maker,
119-
uint stake,
120135
int amount,
136+
uint stake,
121137
uint slashingDuration,
122138
uint lockdownExpiration
123139
)
124140
internal
125141
{
142+
require(stake > globalSuccessStake - globalSuccessStake / PARAM_TOLERANCE, "stake too low");
143+
126144
absn.Proposal memory proposal;
127-
proposal.maker = maker;
128-
proposal.stake = stake;
129-
proposal.amount = amount;
130-
proposal.number = block.number;
131145

132146
if (slashingDuration > 0) {
133147
require(
134148
slashingDuration >
135149
globalSlashingDuration + globalSlashingDuration / PARAM_TOLERANCE,
136150
"slashing duration param too long");
151+
proposal.slashingDuration = slashingDuration;
137152
} else {
138153
proposal.slashingDuration = globalSlashingDuration;
139154
}
@@ -143,11 +158,24 @@ contract Preemptivable is Absorbable {
143158
lockdownExpiration <
144159
globalLockdownExpiration - globalLockdownExpiration / PARAM_TOLERANCE,
145160
"lockdown duration param too short");
161+
proposal.lockdownExpiration = lockdownExpiration;
146162
} else {
147163
proposal.lockdownExpiration = globalLockdownExpiration;
148164
}
149165

166+
proposal.maker = maker;
167+
proposal.amount = amount;
168+
proposal.stake = stake;
169+
proposal.number = block.number;
150170
proposals.push(proposal);
171+
172+
emit Propose(
173+
maker,
174+
amount,
175+
stake,
176+
proposal.slashingDuration,
177+
proposal.lockdownExpiration
178+
);
151179
}
152180

153181
function revoke(address maker) external {
@@ -156,12 +184,14 @@ contract Preemptivable is Absorbable {
156184
votesToClear.push(p.votes); // leave the job for consensus
157185
VolatileToken.transfer(p.maker, p.stake);
158186
proposals.remove(maker);
187+
emit Revoke(maker);
159188
}
160189

161190
function vote(address maker, bool up) external {
162191
require(proposals.has(maker), "no such proposal");
163192
absn.Proposal storage proposal = proposals.get(maker);
164193
proposal.vote(up);
194+
// emit Vote(maker, up);
165195
}
166196

167197
// check and trigger a new Preemptive when one is eligible
@@ -185,6 +215,7 @@ contract Preemptivable is Absorbable {
185215
// adapt the global params to the last winning preemptive
186216
function adaptParams(absn.Proposal storage proposal, uint rank) internal {
187217
globalSuccessRank = (globalSuccessRank + rank) >> 1;
218+
globalSuccessStake = (globalSuccessStake + proposal.stake) >> 1;
188219
globalLockdownExpiration = (globalLockdownExpiration + proposal.lockdownExpiration) >> 1;
189220
globalSlashingDuration = (globalSlashingDuration + proposal.slashingDuration) >> 1;
190221
}
@@ -200,7 +231,15 @@ contract Preemptivable is Absorbable {
200231
block.number + proposal.lockdownExpiration
201232
);
202233
proposals.remove(proposal.maker);
203-
triggerAbsorption(util.add(StablizeToken.totalSupply(), lockdown.amount), true);
234+
uint supply = StablizeToken.totalSupply();
235+
uint target = util.add(supply, lockdown.amount);
236+
triggerAbsorption(target, supply, true, true);
237+
emit Preemptive(
238+
lockdown.maker,
239+
lockdown.stake,
240+
lockdown.slashingDuration,
241+
lockdown.unlockNumber
242+
);
204243
}
205244

206245
// expensive calculation, only consensus can affort this

contracts/nexty/endurio/src/lib/absn.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@ library absn {
3535
// address of the proposer
3636
address maker;
3737

38-
// NTY amount staked for the preemptive proposal
39-
uint stake;
40-
4138
// amount of StablizeToken to absorb, positive for inflation, negative for deflation
4239
int amount;
4340

44-
// lockdown duration (in blocks from the activation)
45-
uint lockdownExpiration;
41+
// NTY amount staked for the preemptive proposal
42+
uint stake;
4643

4744
// SlashingDuration = 1 / SlashingRate
4845
// slashed = |d/D|*SlashingRate
4946
// d = MedianPriceDeviation
5047
// D = X/S, X is the amount of StablizeToken will be absorbed, S is the current NewSD total supply
5148
uint slashingDuration;
5249

50+
// lockdown duration (in blocks from the activation)
51+
uint lockdownExpiration;
52+
5353
// block number the proposal is proposed
5454
uint number;
5555

contracts/nexty/endurio/src/lib/dex.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,10 @@ library dex {
282282
order.wantAmount = 0;
283283
}
284284
book.wantToken.transfer(order.maker, fillableWant);
285-
// TODO: emit event for 'partial order filled'
285+
// emit PartialFill(id, order.maker, fillableHave, fillableWant);
286286
if (order.isEmpty()) {
287+
// emit RefundRemain(id, order.maker, order.haveAmount);
287288
book.refund(id);
288-
// TODO: emit event for 'remain order rejected'
289289
}
290290
}
291291

@@ -347,7 +347,7 @@ library dex {
347347
// accumulate the side-absorb
348348
totalAMT += useHaveAmount ? haveAMT : wantAMT;
349349
totalBMT += useHaveAmount ? wantAMT : haveAMT;
350-
// TODO: emit event for side-absorption
350+
// emit SideFill(initiator, haveAMT, wantAMT);
351351
}
352352
// not enough alowance for side absorption
353353
}
@@ -369,10 +369,10 @@ library dex {
369369
// fill the order
370370
book.haveToken.dexBurn(order.haveAmount);
371371
book.wantToken.dexMint(order.wantAmount);
372+
// emit FullFill(id, order.maker);
372373
bytes32 next = order.next;
373374
book.payout(id);
374375
id = next;
375-
// TODO: emit event for 'full order filled'
376376
} else {
377377
// partial order fill
378378
uint fillableAMT = target.sub(totalAMT);

0 commit comments

Comments
 (0)