@superfluid-finance/ethereum-contracts 1.3.2-dev.bf84335.0 → 1.3.2-dev.ccb1898.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/contracts/AccessControl.json +1 -1
- package/build/contracts/AccessControlEnumerable.json +1 -1
- package/build/contracts/Address.json +1 -1
- package/build/contracts/AgreementBase.json +18 -18
- package/build/contracts/AgreementLibrary.json +1272 -1183
- package/build/contracts/BaseRelayRecipient.json +55 -55
- package/build/contracts/BatchLiquidator.json +211 -211
- package/build/contracts/BatchOperation.json +599 -599
- package/build/contracts/CFAv1Library.json +2282 -2282
- package/build/contracts/CallUtils.json +198 -198
- package/build/contracts/ClosingOnUpdateFlowTestApp.json +2472 -2472
- package/build/contracts/ConstantFlowAgreementV1.json +12931 -13308
- package/build/contracts/Context.json +1 -1
- package/build/contracts/ContextDefinitions.json +599 -599
- package/build/contracts/Create2.json +1 -1
- package/build/contracts/CustomSuperTokenBase.json +20 -20
- package/build/contracts/ERC165.json +1 -1
- package/build/contracts/ERC1820Implementer.json +1 -1
- package/build/contracts/ERC1820RegistryCompiled.json +22 -22
- package/build/contracts/ERC20.json +1 -1
- package/build/contracts/ERC20Burnable.json +1 -1
- package/build/contracts/ERC20Pausable.json +1 -1
- package/build/contracts/ERC20PresetMinterPauser.json +1 -1
- package/build/contracts/ERC20WithTokenInfo.json +23 -23
- package/build/contracts/ERC777Helper.json +380 -380
- package/build/contracts/ERC777RecipientDrainingGas.json +858 -858
- package/build/contracts/ERC777RecipientReverting.json +858 -858
- package/build/contracts/EnumerableSet.json +1 -1
- package/build/contracts/EventsEmitter.json +43 -43
- package/build/contracts/ExclusiveInflowTestApp.json +2473 -2473
- package/build/contracts/FixedSizeData.json +200 -200
- package/build/contracts/FlowExchangeTestApp.json +2473 -2473
- package/build/contracts/FlowOperatorDefinitions.json +599 -599
- package/build/contracts/FullUpgradableSuperTokenProxy.json +115 -115
- package/build/contracts/IAccessControl.json +1 -1
- package/build/contracts/IAccessControlEnumerable.json +1 -1
- package/build/contracts/IConstantFlowAgreementV1.json +567 -567
- package/build/contracts/IDAv1Library.json +2614 -2614
- package/build/contracts/IERC165.json +1 -1
- package/build/contracts/IERC1820Implementer.json +1 -1
- package/build/contracts/IERC1820Registry.json +1 -1
- package/build/contracts/IERC20.json +1 -1
- package/build/contracts/IERC20Metadata.json +1 -1
- package/build/contracts/IERC20Permit.json +1 -1
- package/build/contracts/IERC777.json +1 -1
- package/build/contracts/IERC777Recipient.json +1 -1
- package/build/contracts/IERC777Sender.json +1 -1
- package/build/contracts/IInstantDistributionAgreementV1.json +640 -640
- package/build/contracts/IMaticBridgedNativeSuperToken.json +63 -63
- package/build/contracts/IMaticBridgedNativeSuperTokenCustom.json +63 -63
- package/build/contracts/IMultiSigWallet.json +24 -24
- package/build/contracts/IPureSuperToken.json +43 -43
- package/build/contracts/IPureSuperTokenCustom.json +43 -43
- package/build/contracts/IRelayRecipient.json +27 -27
- package/build/contracts/IResolver.json +38 -38
- package/build/contracts/ISETH.json +48 -48
- package/build/contracts/ISETHCustom.json +48 -48
- package/build/contracts/ISuperAgreement.json +50 -50
- package/build/contracts/ISuperApp.json +192 -192
- package/build/contracts/ISuperToken.json +524 -524
- package/build/contracts/ISuperTokenFactory.json +161 -161
- package/build/contracts/ISuperfluid.json +1145 -1178
- package/build/contracts/ISuperfluidGovernance.json +243 -243
- package/build/contracts/ISuperfluidToken.json +389 -389
- package/build/contracts/ITOGAv1.json +1442 -1442
- package/build/contracts/ITOGAv2.json +1442 -1442
- package/build/contracts/Initializable.json +1 -1
- package/build/contracts/InstantDistributionAgreementV1.json +5820 -5820
- package/build/contracts/MaticBridgedNativeSuperTokenProxy.json +231 -231
- package/build/contracts/NonClosableOutflowTestApp.json +2473 -2473
- package/build/contracts/Ownable.json +1 -1
- package/build/contracts/Pausable.json +1 -1
- package/build/contracts/Proxy.json +1 -1
- package/build/contracts/PureSuperToken.json +109 -109
- package/build/contracts/Resolver.json +98 -98
- package/build/contracts/SETHProxy.json +227 -227
- package/build/contracts/SafeCast.json +1 -1
- package/build/contracts/SafeERC20.json +1 -1
- package/build/contracts/SafeMath.json +1 -1
- package/build/contracts/SelfDeletingFlowTestApp.json +2472 -2472
- package/build/contracts/SlotsBitmapLibrary.json +457 -457
- package/build/contracts/StreamRedirector.json +748 -748
- package/build/contracts/Strings.json +1 -1
- package/build/contracts/SuperAppBase.json +240 -240
- package/build/contracts/SuperAppDefinitions.json +599 -599
- package/build/contracts/SuperToken.json +4732 -4732
- package/build/contracts/SuperTokenFactory.json +750 -750
- package/build/contracts/SuperTokenFactoryBase.json +738 -738
- package/build/contracts/SuperTokenFactoryHelper.json +743 -743
- package/build/contracts/SuperUpgrader.json +440 -440
- package/build/contracts/Superfluid.json +15366 -16050
- package/build/contracts/SuperfluidFrameworkDeployer.json +765 -765
- package/build/contracts/SuperfluidGovernanceBase.json +2233 -2233
- package/build/contracts/SuperfluidGovernanceConfigs.json +599 -599
- package/build/contracts/SuperfluidGovernanceII.json +149 -149
- package/build/contracts/SuperfluidGovernanceIIProxy.json +131 -131
- package/build/contracts/SuperfluidLoader.json +210 -210
- package/build/contracts/SuperfluidToken.json +2420 -2420
- package/build/contracts/TOGA.json +1461 -1461
- package/build/contracts/TestGovernance.json +248 -248
- package/build/contracts/TestToken.json +93 -93
- package/build/contracts/TokenCustodian.json +214 -214
- package/build/contracts/TokenInfo.json +32 -32
- package/build/contracts/UUPSProxiable.json +139 -139
- package/build/contracts/UUPSProxy.json +81 -81
- package/build/contracts/UUPSUtils.json +37 -37
- package/build/contracts-sizes.txt +6 -6
- package/contracts/agreements/AgreementLibrary.sol +39 -15
- package/contracts/agreements/ConstantFlowAgreementV1.sol +65 -53
- package/contracts/interfaces/superfluid/ISuperfluid.sol +29 -23
- package/contracts/mocks/AgreementMock.sol +2 -2
- package/contracts/mocks/CFAAppMocks.sol +1 -1
- package/contracts/mocks/MultiFlowTesterApp.sol +13 -12
- package/contracts/mocks/SuperTokenMock.sol +2 -2
- package/contracts/mocks/SuperfluidMock.sol +9 -9
- package/contracts/superfluid/Superfluid.sol +34 -38
- package/contracts/superfluid/SuperfluidToken.sol +14 -14
- package/package.json +2 -2
- package/scripts/deploy-mfa.ts +27 -0
- package/scripts/libs/getConfig.js +14 -0
- package/utils/README.md +18 -0
- package/utils/mfa-tester.html +687 -0
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<title>Multi Flow Block Explorer</title>
|
|
6
|
+
<meta charset="utf-8" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
|
8
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css"
|
|
9
|
+
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
|
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/ethers@5.6.0/dist/ethers.umd.min.js"
|
|
11
|
+
integrity="sha256-I/T7C/qM1p/EIawMnVp+b68aGIgHpiaW5uJm8Xd/WYg=" crossorigin="anonymous"></script>
|
|
12
|
+
|
|
13
|
+
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P" rel="stylesheet">
|
|
14
|
+
<!-- minify -->
|
|
15
|
+
<link href="https://unpkg.com/nes.css@2.3.0/css/nes.min.css" rel="stylesheet" />
|
|
16
|
+
|
|
17
|
+
<!-- sdk-core -->
|
|
18
|
+
<script src="./dist/index.umd.js"></script>
|
|
19
|
+
<!-- vue.js -->
|
|
20
|
+
<script type="importmap">
|
|
21
|
+
{
|
|
22
|
+
"imports": {
|
|
23
|
+
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
<style>
|
|
28
|
+
html, body, input, select {
|
|
29
|
+
color: #10BB35;
|
|
30
|
+
background: #151619 !important;
|
|
31
|
+
outline: none;
|
|
32
|
+
}
|
|
33
|
+
label {
|
|
34
|
+
display: table-cell;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
input {
|
|
38
|
+
display: table-cell;
|
|
39
|
+
}
|
|
40
|
+
input, select {
|
|
41
|
+
border: 1px solid #10BB35;
|
|
42
|
+
}
|
|
43
|
+
p {
|
|
44
|
+
margin-bottom: 0;
|
|
45
|
+
color: #10BB35;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.input-table {
|
|
49
|
+
display: table;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.input-container {
|
|
53
|
+
display: table-row;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.receiver-container {
|
|
57
|
+
margin-bottom: 1rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.loading {
|
|
61
|
+
width: 100vw;
|
|
62
|
+
height: 100vh;
|
|
63
|
+
z-index: 2;
|
|
64
|
+
position: absolute;
|
|
65
|
+
background-color: black;
|
|
66
|
+
opacity: 0.3;
|
|
67
|
+
top: 0;
|
|
68
|
+
left: 0;
|
|
69
|
+
color: white;
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
72
|
+
|
|
73
|
+
</head>
|
|
74
|
+
|
|
75
|
+
<body>
|
|
76
|
+
<script type="module">
|
|
77
|
+
import { computed, createApp, reactive, ref, onMounted, watch } from 'vue';
|
|
78
|
+
|
|
79
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
80
|
+
const RESOLVER_ADDRESS = "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512";
|
|
81
|
+
const MFA_ADDRESS = "0x9E545E3C0baAB3E08CdfD552C960A1050f373042";
|
|
82
|
+
const EMPTY_RECEIVER = { address: ZERO_ADDRESS, proportion: "0" };
|
|
83
|
+
const RESET_SNAPSHOT_ID = "RESET_SNAPSHOT";
|
|
84
|
+
|
|
85
|
+
createApp({
|
|
86
|
+
setup() {
|
|
87
|
+
let framework;
|
|
88
|
+
let token;
|
|
89
|
+
let passedSigner;
|
|
90
|
+
const provider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545/");
|
|
91
|
+
const abiCoder = new ethers.utils.AbiCoder();
|
|
92
|
+
|
|
93
|
+
// computed properties
|
|
94
|
+
const mfaData = reactive({ ratioPct: "", flowRate: "", mfaAddress: MFA_ADDRESS, signerAddress: "" });
|
|
95
|
+
const receivers = reactive([]); // Array<{ address: string, proportion: string }>
|
|
96
|
+
const accounts = reactive([]); // Array<string>
|
|
97
|
+
const tokenData = reactive({
|
|
98
|
+
address: "",
|
|
99
|
+
balance: 0,
|
|
100
|
+
name: "",
|
|
101
|
+
underlyingAddress: "",
|
|
102
|
+
underlyingBalance: 0,
|
|
103
|
+
underlyingName: "",
|
|
104
|
+
});
|
|
105
|
+
const balanceData = reactive({
|
|
106
|
+
sender: {},
|
|
107
|
+
mfa: {},
|
|
108
|
+
receivers: []
|
|
109
|
+
});
|
|
110
|
+
const agreementData = reactive({
|
|
111
|
+
senderToMfa: {},
|
|
112
|
+
mfaToReceivers: []
|
|
113
|
+
});
|
|
114
|
+
const flowData = reactive({
|
|
115
|
+
flowRate: "",
|
|
116
|
+
sender: "",
|
|
117
|
+
receiver: ""
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const receiverAddresses = computed(() => receivers.map(x => x.address));
|
|
121
|
+
const filteredReceivers = computed(() => receivers.filter(x => x.proportion > 0));
|
|
122
|
+
const signerAddress = computed(() => signer && signer.value ? signer.value._address : "n/a");
|
|
123
|
+
const providerNetwork = computed(() => provider && provider ? provider._network : "n/a");
|
|
124
|
+
|
|
125
|
+
// reactive refs
|
|
126
|
+
const selected = ref("");
|
|
127
|
+
const currentToken = ref("ETHx");
|
|
128
|
+
const currentReceiverAddress = ref("");
|
|
129
|
+
const currentReceiverProportion = ref("");
|
|
130
|
+
const impersonatedSignerAddress = ref("");
|
|
131
|
+
const increaseTimeSeconds = ref("");
|
|
132
|
+
const signer = ref(null);
|
|
133
|
+
const loading = ref(true);
|
|
134
|
+
const balanceSum = ref("");
|
|
135
|
+
const blockTimestamp = ref("");
|
|
136
|
+
|
|
137
|
+
// watchers
|
|
138
|
+
watch(selected, (receiverAddress) => {
|
|
139
|
+
const receiver = receivers.find(x => x.address === receiverAddress);
|
|
140
|
+
if (receiver) {
|
|
141
|
+
currentReceiverProportion.value = receiver.proportion;
|
|
142
|
+
currentReceiverAddress.value = receiverAddress;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
watch(signer, async (signer) => {
|
|
146
|
+
if (token) {
|
|
147
|
+
const { superTokenBalanceData, underlyingBalance } = await getBalanceData(signer._address);
|
|
148
|
+
tokenData.balance = superTokenBalanceData.availableBalance;
|
|
149
|
+
tokenData.underlyingBalance = toBN(underlyingBalance);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
watch(accounts, async (accounts) => {
|
|
153
|
+
try {
|
|
154
|
+
if (accounts.length > 0) {
|
|
155
|
+
await initialize();
|
|
156
|
+
const { superTokenBalanceData } = await getBalanceData(signer.value._address);
|
|
157
|
+
const signers = await getSigners();
|
|
158
|
+
if (Number(superTokenBalanceData.availableBalance) === 0) {
|
|
159
|
+
const upgradePromise = signers.map(x => upgradeToSuperToken(x));
|
|
160
|
+
await Promise.all(upgradePromise);
|
|
161
|
+
}
|
|
162
|
+
await loadToken();
|
|
163
|
+
await getAndSetSumBalance(signers.map(x => x._address));
|
|
164
|
+
}
|
|
165
|
+
if (!sessionStorage.getItem(RESET_SNAPSHOT_ID)) {
|
|
166
|
+
const snapshotId = await takeSnapshotAndReturnId();
|
|
167
|
+
sessionStorage.setItem(RESET_SNAPSHOT_ID, snapshotId);
|
|
168
|
+
}
|
|
169
|
+
} catch (err) {
|
|
170
|
+
console.error(err);
|
|
171
|
+
} finally {
|
|
172
|
+
loading.value = false;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const hasValidMFAInput = () => {
|
|
177
|
+
return mfaData.ratioPct !== ""
|
|
178
|
+
&& mfaData.flowRate !== ""
|
|
179
|
+
&& isAddress(mfaData.signerAddress)
|
|
180
|
+
&& filteredReceivers.value.length > 0;
|
|
181
|
+
}
|
|
182
|
+
const isAddress = (address) => {
|
|
183
|
+
return ethers.utils.isAddress(address);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// receivers crud
|
|
187
|
+
const addReceiver = () => {
|
|
188
|
+
let newAddress;
|
|
189
|
+
if (currentReceiverAddress.value !== "" || currentReceiverProportion.value !== "") {
|
|
190
|
+
|
|
191
|
+
const currentData = {
|
|
192
|
+
address: currentReceiverAddress.value,
|
|
193
|
+
proportion: currentReceiverProportion.value
|
|
194
|
+
};
|
|
195
|
+
receivers.push(currentData);
|
|
196
|
+
newAddress = currentReceiverAddress.value;
|
|
197
|
+
} else {
|
|
198
|
+
receivers.push(EMPTY_RECEIVER);
|
|
199
|
+
newAddress = EMPTY_RECEIVER.address;
|
|
200
|
+
}
|
|
201
|
+
selected.value = newAddress;
|
|
202
|
+
};
|
|
203
|
+
const updateReceiver = () => {
|
|
204
|
+
const i = receivers.map(x => x.address).indexOf(selected.value);
|
|
205
|
+
receivers[i].address = selected.value = currentReceiverAddress.value;
|
|
206
|
+
receivers[i].proportion = currentReceiverProportion.value;
|
|
207
|
+
selected.value = currentReceiverAddress.value = currentReceiverProportion.value = "";
|
|
208
|
+
};
|
|
209
|
+
const removeReceiver = (receiver) => {
|
|
210
|
+
const i = receivers.map(x => x.address).indexOf(selected.value);
|
|
211
|
+
receivers.splice(i, 1);
|
|
212
|
+
selected.value = currentReceiverAddress.value = currentReceiverProportion.value = ""
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// data formatting
|
|
216
|
+
const toBN = (num) => ethers.BigNumber.from(num);
|
|
217
|
+
const getPerSecondFlowRateByDay = (amountPerDay) => {
|
|
218
|
+
return Math.round(
|
|
219
|
+
(Number(amountPerDay) / 86400) * 10 ** 18
|
|
220
|
+
).toString();
|
|
221
|
+
};
|
|
222
|
+
const getMFAUserData = () => {
|
|
223
|
+
return abiCoder.encode(
|
|
224
|
+
[
|
|
225
|
+
"address",
|
|
226
|
+
"uint256",
|
|
227
|
+
"address[]",
|
|
228
|
+
"uint256[]"
|
|
229
|
+
],
|
|
230
|
+
[
|
|
231
|
+
mfaData.signerAddress,
|
|
232
|
+
mfaData.ratioPct || "0",
|
|
233
|
+
filteredReceivers.value.map(x => x.address),
|
|
234
|
+
filteredReceivers.value.map(x => x.proportion)
|
|
235
|
+
]);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// text formatting
|
|
239
|
+
const formatBalance = (balance) => Number(ethers.utils.formatEther(toBN(balance || "0"))).toFixed(18);
|
|
240
|
+
|
|
241
|
+
// async
|
|
242
|
+
const getBalanceData = async (signerAddress) => {
|
|
243
|
+
const isNativeAsset = token.nativeTokenSymbol !== "";
|
|
244
|
+
const balanceData = await token.realtimeBalanceOf({
|
|
245
|
+
providerOrSigner: provider,
|
|
246
|
+
account: signerAddress,
|
|
247
|
+
timestamp: blockTimestamp.value || Math.floor(new Date().getTime() / 1000).toString()
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
const underlyingBalance = await provider.getBalance(signerAddress);
|
|
251
|
+
return { superTokenBalanceData: balanceData, underlyingBalance };
|
|
252
|
+
}
|
|
253
|
+
const getFlowData = async (sender, receiver) =>
|
|
254
|
+
({
|
|
255
|
+
...await token.getFlow({
|
|
256
|
+
sender,
|
|
257
|
+
receiver,
|
|
258
|
+
providerOrSigner: provider
|
|
259
|
+
}),
|
|
260
|
+
address: receiver
|
|
261
|
+
});
|
|
262
|
+
const getAccountNetFlow = async (account) =>
|
|
263
|
+
await token.getNetFlow({
|
|
264
|
+
account,
|
|
265
|
+
providerOrSigner: provider
|
|
266
|
+
});
|
|
267
|
+
const getFlowAndBalanceData = async (account) => {
|
|
268
|
+
const { superTokenBalanceData } = await getBalanceData(account);
|
|
269
|
+
const flowRate = await getAccountNetFlow(account);
|
|
270
|
+
return {
|
|
271
|
+
availableBalance: superTokenBalanceData.availableBalance,
|
|
272
|
+
deposit: superTokenBalanceData.deposit,
|
|
273
|
+
owedDeposit: superTokenBalanceData.owedDeposit,
|
|
274
|
+
flowRate,
|
|
275
|
+
address: account
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const loadToken = async () => {
|
|
279
|
+
const superToken = await framework.loadSuperToken(currentToken.value);
|
|
280
|
+
token = superToken;
|
|
281
|
+
tokenData.address = superToken.address;
|
|
282
|
+
if (signer.value) {
|
|
283
|
+
const { superTokenBalanceData, underlyingBalance } = await getBalanceData(signer.value._address);
|
|
284
|
+
tokenData.balance = superTokenBalanceData.availableBalance;
|
|
285
|
+
tokenData.underlyingBalance = underlyingBalance;
|
|
286
|
+
}
|
|
287
|
+
tokenData.name = await superToken.symbol({
|
|
288
|
+
providerOrSigner: provider
|
|
289
|
+
});
|
|
290
|
+
tokenData.underlyingName = superToken.nativeTokenSymbol
|
|
291
|
+
|| await superToken.underlyingToken.connect(provider).symbol();
|
|
292
|
+
}
|
|
293
|
+
const getAccounts = async () => {
|
|
294
|
+
const ethAccounts = await provider.listAccounts();
|
|
295
|
+
accounts.push(...ethAccounts);
|
|
296
|
+
}
|
|
297
|
+
const getSigners = async () => {
|
|
298
|
+
const signersPromise = accounts.map(x => provider.getSigner(x));
|
|
299
|
+
return await Promise.all(signersPromise);
|
|
300
|
+
}
|
|
301
|
+
const getAndSetSumBalance = async (addresses) => {
|
|
302
|
+
const addressBalances = await Promise.all([...addresses, mfaData.mfaAddress].map(x => getBalanceData(x)));
|
|
303
|
+
const stbds = addressBalances.map(x => x.superTokenBalanceData);
|
|
304
|
+
const abSum = stbds.map(x => x.availableBalance).reduce((a, b) => toBN(a).add(toBN(b)), toBN(0));
|
|
305
|
+
const depSum = stbds.map(x => x.deposit).reduce((a, b) => toBN(a).add(toBN(b)), toBN(0));
|
|
306
|
+
const odSum = stbds.map(x => x.owedDeposit).reduce((a, b) => toBN(a).add(toBN(b)), toBN(0));
|
|
307
|
+
|
|
308
|
+
balanceSum.value = abSum.add(depSum).sub(odSum);
|
|
309
|
+
console.log("BALANCE SUM:", formatBalance(balanceSum.value));
|
|
310
|
+
console.log("AVB SUM (+):", formatBalance(abSum));
|
|
311
|
+
console.log("DEP SUM (+):", formatBalance(depSum));
|
|
312
|
+
console.log("ODE SUM (-):", formatBalance(odSum));
|
|
313
|
+
}
|
|
314
|
+
const impersonateAccount = async () => {
|
|
315
|
+
await provider.send(
|
|
316
|
+
"hardhat_impersonateAccount",
|
|
317
|
+
[mfaData.signerAddress]
|
|
318
|
+
);
|
|
319
|
+
const ethersSigner = await provider.getSigner(mfaData.signerAddress);
|
|
320
|
+
signer.value = ethersSigner;
|
|
321
|
+
passedSigner = ethersSigner;
|
|
322
|
+
}
|
|
323
|
+
const _increaseTime = async (seconds) => {
|
|
324
|
+
await provider.send("evm_increaseTime", [seconds]);
|
|
325
|
+
await provider.send("evm_mine", []);
|
|
326
|
+
}
|
|
327
|
+
const increaseTime = async () => {
|
|
328
|
+
await _increaseTime(Number(increaseTimeSeconds.value));
|
|
329
|
+
await getAndSetCurrentBlockTimestamp();
|
|
330
|
+
await loadToken();
|
|
331
|
+
await setupData();
|
|
332
|
+
await getAndSetSumBalance(accounts.map(x => x));
|
|
333
|
+
}
|
|
334
|
+
const getAndSetCurrentBlockTimestamp = async () => {
|
|
335
|
+
const block = await provider.getBlock();
|
|
336
|
+
blockTimestamp.value = block.timestamp;
|
|
337
|
+
}
|
|
338
|
+
const takeSnapshotAndReturnId = async () => {
|
|
339
|
+
return await provider.send(
|
|
340
|
+
"evm_snapshot",
|
|
341
|
+
[]
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
const revertToSnapshot = async (snapshotId) => {
|
|
345
|
+
await provider.send(
|
|
346
|
+
"evm_revert",
|
|
347
|
+
[snapshotId]
|
|
348
|
+
);
|
|
349
|
+
return await takeSnapshotAndReturnId();
|
|
350
|
+
}
|
|
351
|
+
const resetState = async () => {
|
|
352
|
+
try {
|
|
353
|
+
const snapshotId = sessionStorage.getItem(RESET_SNAPSHOT_ID);
|
|
354
|
+
const newId = await revertToSnapshot(snapshotId);
|
|
355
|
+
sessionStorage.setItem(RESET_SNAPSHOT_ID, newId);
|
|
356
|
+
await setupData();
|
|
357
|
+
} catch (err) {
|
|
358
|
+
console.error(err);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const setupData = async () => {
|
|
362
|
+
const senderData = await getFlowAndBalanceData(mfaData.signerAddress);
|
|
363
|
+
const mfaFlowData = await getFlowAndBalanceData(mfaData.mfaAddress);
|
|
364
|
+
const mfaToReceiversData = await Promise.all(
|
|
365
|
+
accounts.map(x => getFlowData(mfaData.mfaAddress, x))
|
|
366
|
+
);
|
|
367
|
+
const mfaReceivers = mfaToReceiversData.filter(x => x.flowRate > 0).map(x => x.address);
|
|
368
|
+
const filteredReceiversData = await Promise.all(mfaReceivers.map(x => getFlowAndBalanceData(x)));
|
|
369
|
+
balanceData.sender = senderData;
|
|
370
|
+
balanceData.mfa = mfaFlowData;
|
|
371
|
+
balanceData.receivers = filteredReceiversData;
|
|
372
|
+
|
|
373
|
+
agreementData.senderToMfa = await getFlowData(mfaData.signerAddress, mfaData.mfaAddress);
|
|
374
|
+
agreementData.mfaToReceivers = await Promise.all(mfaReceivers.map(x => getFlowData(mfaData.mfaAddress, x)));
|
|
375
|
+
receivers.splice(0, receivers.length);
|
|
376
|
+
receivers.push(
|
|
377
|
+
...filteredReceiversData.map(x => ({ address: x.address, proportion: 1 }))
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
/** initialize signer, framework, token */
|
|
381
|
+
const initialize = async () => {
|
|
382
|
+
mfaData.signerAddress = accounts[0];
|
|
383
|
+
await impersonateAccount();
|
|
384
|
+
const sf = await sdkCore.Framework.create({
|
|
385
|
+
chainId: 31337,
|
|
386
|
+
provider: provider,
|
|
387
|
+
resolverAddress: RESOLVER_ADDRESS,
|
|
388
|
+
protocolReleaseVersion: "test",
|
|
389
|
+
});
|
|
390
|
+
framework = sf;
|
|
391
|
+
await getAndSetCurrentBlockTimestamp();
|
|
392
|
+
await loadToken();
|
|
393
|
+
await setupData();
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// transaction functions
|
|
397
|
+
const upgradeToSuperToken = async (signer) => {
|
|
398
|
+
const ethBalance = await provider.getBalance(signer._address);
|
|
399
|
+
await token.upgrade({ amount: ethers.utils.parseUnits("100") }).exec(signer);
|
|
400
|
+
}
|
|
401
|
+
const _modifyStream = async (action, sender, receiver, flowRate, isMfa) => {
|
|
402
|
+
loading.value = true;
|
|
403
|
+
try {
|
|
404
|
+
console.log("modifying stream:", action);
|
|
405
|
+
if (signer.value == null) {
|
|
406
|
+
await impersonateAccount();
|
|
407
|
+
}
|
|
408
|
+
const s = await provider.getSigner(signer.value._address);
|
|
409
|
+
const userData = isMfa ? getMFAUserData() : "0x";
|
|
410
|
+
const txn = action === "create" ?
|
|
411
|
+
await token.createFlow({
|
|
412
|
+
receiver,
|
|
413
|
+
flowRate: getPerSecondFlowRateByDay(flowRate),
|
|
414
|
+
userData
|
|
415
|
+
}).exec(s)
|
|
416
|
+
: action === "update"
|
|
417
|
+
? await token.updateFlow({
|
|
418
|
+
receiver,
|
|
419
|
+
flowRate: getPerSecondFlowRateByDay(flowRate),
|
|
420
|
+
userData
|
|
421
|
+
}).exec(s)
|
|
422
|
+
: await token.deleteFlow({
|
|
423
|
+
sender,
|
|
424
|
+
receiver,
|
|
425
|
+
userData
|
|
426
|
+
}).exec(s);
|
|
427
|
+
const receipt = await txn.wait();
|
|
428
|
+
|
|
429
|
+
console.log("RECEIPT", receipt);
|
|
430
|
+
const block = await provider.getBlock(receipt.blockNumber);
|
|
431
|
+
blockTimestamp.value = block.timestamp;
|
|
432
|
+
await setupData();
|
|
433
|
+
await getAndSetSumBalance(accounts.map(x => x));
|
|
434
|
+
} catch (err) {
|
|
435
|
+
console.error(err);
|
|
436
|
+
} finally {
|
|
437
|
+
loading.value = false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
const senderToMfaModifyStream = async (action) => {
|
|
441
|
+
_modifyStream(action, signer.value._address, mfaData.mfaAddress || MFA_ADDRESS, mfaData.flowRate, true);
|
|
442
|
+
}
|
|
443
|
+
const modifyStream = async (action) => {
|
|
444
|
+
_modifyStream(action, flowData.sender, flowData.receiver, flowData.flowRate, false);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// initialization
|
|
448
|
+
getAccounts();
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
addReceiver,
|
|
452
|
+
formatBalance,
|
|
453
|
+
hasValidMFAInput,
|
|
454
|
+
impersonateAccount,
|
|
455
|
+
increaseTime,
|
|
456
|
+
isAddress,
|
|
457
|
+
loadToken,
|
|
458
|
+
modifyStream,
|
|
459
|
+
removeReceiver,
|
|
460
|
+
resetState,
|
|
461
|
+
senderToMfaModifyStream,
|
|
462
|
+
updateReceiver,
|
|
463
|
+
|
|
464
|
+
accounts,
|
|
465
|
+
agreementData,
|
|
466
|
+
balanceData,
|
|
467
|
+
balanceSum,
|
|
468
|
+
blockTimestamp,
|
|
469
|
+
currentReceiverAddress,
|
|
470
|
+
currentReceiverProportion,
|
|
471
|
+
currentToken,
|
|
472
|
+
filteredReceivers,
|
|
473
|
+
flowData,
|
|
474
|
+
impersonatedSignerAddress,
|
|
475
|
+
increaseTimeSeconds,
|
|
476
|
+
loading,
|
|
477
|
+
mfaData,
|
|
478
|
+
providerNetwork,
|
|
479
|
+
receiverAddresses,
|
|
480
|
+
receivers,
|
|
481
|
+
selected,
|
|
482
|
+
signer,
|
|
483
|
+
signerAddress,
|
|
484
|
+
token,
|
|
485
|
+
tokenData,
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}).mount('#app')
|
|
489
|
+
</script>
|
|
490
|
+
</body>
|
|
491
|
+
<div id="app">
|
|
492
|
+
<h1 class="loading d-flex justify-content-center align-items-center" v-if="loading">loading...</h1>
|
|
493
|
+
<div class="p-3">
|
|
494
|
+
<h2 class="d-flex align-items-center justify-content-center">
|
|
495
|
+
<i class="nes-icon coin is-large"></i>
|
|
496
|
+
<i class="nes-mario"></i>
|
|
497
|
+
Multi Flow Block Explorer
|
|
498
|
+
<i class="nes-mario"></i>
|
|
499
|
+
<i class="nes-icon coin is-large"></i>
|
|
500
|
+
</h2>
|
|
501
|
+
<div>
|
|
502
|
+
<div>
|
|
503
|
+
<div>
|
|
504
|
+
<h4>Global Information</h4>
|
|
505
|
+
<p>
|
|
506
|
+
Balances Sum: {{ formatBalance(balanceSum) }}
|
|
507
|
+
</p>
|
|
508
|
+
<p>
|
|
509
|
+
Current block timestamp: {{ blockTimestamp }}
|
|
510
|
+
</p>
|
|
511
|
+
</div>
|
|
512
|
+
<div>
|
|
513
|
+
<h4>General Information</h4>
|
|
514
|
+
<p>
|
|
515
|
+
Selected Token: {{ tokenData.name }} | {{
|
|
516
|
+
tokenData.address }}
|
|
517
|
+
</p>
|
|
518
|
+
<p>MFA Address: {{ mfaData.mfaAddress }}</p>
|
|
519
|
+
<p>Selected Impersonated Signer: {{ signerAddress }}</p>
|
|
520
|
+
<p>
|
|
521
|
+
Token Balance: {{ formatBalance(tokenData.balance)
|
|
522
|
+
}} {{ tokenData.name }}
|
|
523
|
+
</p>
|
|
524
|
+
<p>
|
|
525
|
+
Underlying Balance: {{
|
|
526
|
+
formatBalance(tokenData.underlyingBalance) }} {{
|
|
527
|
+
tokenData.underlyingName}}
|
|
528
|
+
</p>
|
|
529
|
+
</div>
|
|
530
|
+
<div class="input-table mt-3">
|
|
531
|
+
<div class="input-container">
|
|
532
|
+
<label for="signerAddress">Signer</label>
|
|
533
|
+
<input class="ml-2" type="text" v-model="mfaData.signerAddress" name="signerAddress" />
|
|
534
|
+
<button type="button" class="nes-btn is-primary" @click="impersonateAccount"
|
|
535
|
+
:disabled="!isAddress(mfaData.signerAddress)">
|
|
536
|
+
Impersonate
|
|
537
|
+
</button>
|
|
538
|
+
</div>
|
|
539
|
+
<div class="input-container">
|
|
540
|
+
<label for="mfaAddress">MFA Address</label>
|
|
541
|
+
<input class="ml-2" type="text" v-model="mfaData.mfaAddress" name="mfaAddress" />
|
|
542
|
+
</div>
|
|
543
|
+
<div class="input-container">
|
|
544
|
+
<label for="signerAddress">Token</label>
|
|
545
|
+
<input class="ml-2" type="text" v-model="currentToken" name="currentToken" />
|
|
546
|
+
<button type="button" class="nes-btn is-primary" @click="loadToken">Load Token</button>
|
|
547
|
+
</div>
|
|
548
|
+
<div class="input-container">
|
|
549
|
+
<label for="ratioPct">Ratio Percent</label>
|
|
550
|
+
<input class="ml-2" type="number" v-model="mfaData.ratioPct" name="ratioPct" />
|
|
551
|
+
</div>
|
|
552
|
+
<div class="input-container">
|
|
553
|
+
<label for="flowRate">Flow Rate (/day)</label>
|
|
554
|
+
<input class="ml-2" type="number" v-model="mfaData.flowRate" name="flowRate" />
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
<div class="mt-3">
|
|
558
|
+
<h4>Receivers</h4>
|
|
559
|
+
<select class="mb-3" style="width: 420px" size="5" v-model="selected">
|
|
560
|
+
<option v-for="receiverAddress in receiverAddresses">
|
|
561
|
+
{{receiverAddress}}
|
|
562
|
+
</option>
|
|
563
|
+
</select>
|
|
564
|
+
<div class="input-container">
|
|
565
|
+
<label for="currentReceiverAddress">Receiver Address</label>
|
|
566
|
+
<input class="ml-2" type="text" size="50" v-model="currentReceiverAddress"
|
|
567
|
+
name="currentReceiverAddress" />
|
|
568
|
+
</div>
|
|
569
|
+
<div class="input-container">
|
|
570
|
+
<label for="currentReceiverProportion">Receiver Proportion</label>
|
|
571
|
+
<input class="ml-2" style="width: 69px" type="number" min="0" max="1"
|
|
572
|
+
v-model="currentReceiverProportion" name="currentReceiverProportion" />
|
|
573
|
+
</div>
|
|
574
|
+
<div class="d-flex justify-content-around mt-3 mb-3">
|
|
575
|
+
<button type="button" class="nes-btn is-primary" @click="addReceiver">Add receiver</button>
|
|
576
|
+
<button type="button" class="nes-btn is-primary" @click="updateReceiver" :disabled='selected === ""'>
|
|
577
|
+
Update receiver
|
|
578
|
+
</button>
|
|
579
|
+
<button type="button" class="nes-btn is-primary" @click="removeReceiver" :disabled='selected === ""'>
|
|
580
|
+
Remove receiver
|
|
581
|
+
</button>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
<div class="d-flex justify-content-around mb-3">
|
|
585
|
+
<button type="button" class="nes-btn is-primary" @click='senderToMfaModifyStream("create")'
|
|
586
|
+
:disabled="hasValidMFAInput() === false">
|
|
587
|
+
Start Stream
|
|
588
|
+
</button>
|
|
589
|
+
<button type="button" class="nes-btn is-primary" @click='senderToMfaModifyStream("update")'
|
|
590
|
+
:disabled="hasValidMFAInput() === false">
|
|
591
|
+
Update Stream
|
|
592
|
+
</button>
|
|
593
|
+
<button type="button" class="nes-btn is-primary" @click='senderToMfaModifyStream("delete")'>
|
|
594
|
+
Delete Stream
|
|
595
|
+
</button>
|
|
596
|
+
</div>
|
|
597
|
+
<button type="button" class="nes-btn is-error" @click="resetState">
|
|
598
|
+
Reset to initial state
|
|
599
|
+
</button>
|
|
600
|
+
<div class="input-container">
|
|
601
|
+
<label for="increaseTimeSeconds">Seconds</label>
|
|
602
|
+
<input class="ml-2" type="text" v-model="increaseTimeSeconds" name="increaseTimeSeconds" />
|
|
603
|
+
<button type="button" class="nes-btn is-primary" @click="increaseTime">
|
|
604
|
+
Increase time
|
|
605
|
+
</button>
|
|
606
|
+
</div>
|
|
607
|
+
</div>
|
|
608
|
+
<div>
|
|
609
|
+
<h4>Accounts</h4>
|
|
610
|
+
<ul>
|
|
611
|
+
<li v-for="account in accounts">{{ account }}</li>
|
|
612
|
+
</ul>
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
<h4>Account State</h4>
|
|
616
|
+
<div class="mfa-flows-container d-flex align-items-center justify-content-around">
|
|
617
|
+
<div class="account-container">
|
|
618
|
+
<b>Sender</b>
|
|
619
|
+
<p>available balance: {{ formatBalance(balanceData.sender.availableBalance) }}</p>
|
|
620
|
+
<p>deposit: {{ formatBalance(balanceData.sender.deposit) }}</p>
|
|
621
|
+
<p>owed deposit: {{ formatBalance(balanceData.sender.owedDeposit) }}</p>
|
|
622
|
+
<p>net flow rate: {{ formatBalance(balanceData.sender.flowRate) }}</p>
|
|
623
|
+
</div>
|
|
624
|
+
<div class="account-container">
|
|
625
|
+
<b>MFA</b>
|
|
626
|
+
<p>available balance: {{ formatBalance(balanceData.mfa.availableBalance) }}</p>
|
|
627
|
+
<p>deposit: {{ formatBalance(balanceData.mfa.deposit) }}</p>
|
|
628
|
+
<p>owed deposit: {{ formatBalance(balanceData.mfa.owedDeposit) }}</p>
|
|
629
|
+
<p>net flow rate: {{ formatBalance(balanceData.mfa.flowRate) }}</p>
|
|
630
|
+
</div>
|
|
631
|
+
<div class="d-flex flex-column">
|
|
632
|
+
<div class="receiver-container" v-for="(receiver, i) in balanceData.receivers">
|
|
633
|
+
<b>Receiver {{ i + 1 }}: {{ receiver.address.substring(0, 6) }}</b>
|
|
634
|
+
<p>available balance: {{ formatBalance(receiver.availableBalance) }}</p>
|
|
635
|
+
<p>deposit: {{ formatBalance(receiver.deposit) }}</p>
|
|
636
|
+
<p>owed deposit: {{ formatBalance(receiver.owedDeposit) }}</p>
|
|
637
|
+
<p>net flow rate: {{ formatBalance(receiver.flowRate) }}</p>
|
|
638
|
+
</div>
|
|
639
|
+
</div>
|
|
640
|
+
</div>
|
|
641
|
+
<h4 class="mt-5">Agreement State</h4>
|
|
642
|
+
<div class="mfa-flow-agreements-container d-flex align-items-center justify-content-around">
|
|
643
|
+
<div class="account-container">
|
|
644
|
+
<b>Sender -> MFA</b>
|
|
645
|
+
<p>deposit: {{ formatBalance(agreementData.senderToMfa.deposit) }}</p>
|
|
646
|
+
<p>owed deposit: {{ formatBalance(agreementData.senderToMfa.owedDeposit) }}</p>
|
|
647
|
+
<p>flow rate: {{ formatBalance(agreementData.senderToMfa.flowRate) }}</p>
|
|
648
|
+
</div>
|
|
649
|
+
|
|
650
|
+
<div class="d-flex flex-column">
|
|
651
|
+
<div class="receiver-container" v-for="(receiver, i) in agreementData.mfaToReceivers">
|
|
652
|
+
<b>MFA -> Receiver {{ i + 1 }}: {{ receiver.address.substring(0, 6) }}</b>
|
|
653
|
+
<p>deposit: {{ formatBalance(receiver.deposit) }}</p>
|
|
654
|
+
<p>owed deposit: {{ formatBalance(receiver.owedDeposit) }}</p>
|
|
655
|
+
<p>net flow rate: {{ formatBalance(receiver.flowRate) }}</p>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
</div>
|
|
659
|
+
|
|
660
|
+
<div>
|
|
661
|
+
<h4>Arbitrary Stream Modifications</h4>
|
|
662
|
+
<div class="input-container">
|
|
663
|
+
<label for="sender">Sender</label>
|
|
664
|
+
<input class="ml-2" type="string" v-model="flowData.sender" name="sender" />
|
|
665
|
+
</div>
|
|
666
|
+
<div class="input-container">
|
|
667
|
+
<label for="receiver">Receiver</label>
|
|
668
|
+
<input class="ml-2" type="string" v-model="flowData.receiver" name="receiver" />
|
|
669
|
+
</div>
|
|
670
|
+
<div class="input-container">
|
|
671
|
+
<label for="flowData.flowRate">Flow Rate</label>
|
|
672
|
+
<input class="ml-2" type="string" v-model="flowData.flowRate" name="flowData.flowRate" />
|
|
673
|
+
</div>
|
|
674
|
+
<button type="button" class="nes-btn is-primary" @click='modifyStream("create")'>
|
|
675
|
+
Create Stream
|
|
676
|
+
</button>
|
|
677
|
+
<button type="button" class="nes-btn is-primary" @click='modifyStream("update")'>
|
|
678
|
+
Update Stream
|
|
679
|
+
</button>
|
|
680
|
+
<button type="button" class="nes-btn is-primary" @click='modifyStream("delete")'>
|
|
681
|
+
Delete Stream
|
|
682
|
+
</button>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
|
|
687
|
+
</html>
|