WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit c3d9a45

Browse files
authored
Merge pull request #640 from VenusProtocol/feat/VPD-314
[VPD-314]: Add enterMarketBehalf support to Comptroller
2 parents 401f3fc + fec05a4 commit c3d9a45

File tree

8 files changed

+5856
-0
lines changed

8 files changed

+5856
-0
lines changed

simulations/vip-573/abi/Comptroller.json

Lines changed: 4477 additions & 0 deletions
Large diffs are not rendered by default.

simulations/vip-573/abi/Diamond.json

Lines changed: 957 additions & 0 deletions
Large diffs are not rendered by default.

simulations/vip-573/bscmainnet.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { TransactionResponse } from "@ethersproject/providers";
2+
import { expect } from "chai";
3+
import { Contract } from "ethers";
4+
import { parseEther } from "ethers/lib/utils";
5+
import { ethers } from "hardhat";
6+
import { NETWORK_ADDRESSES } from "src/networkAddresses";
7+
import { expectEvents, initMainnetUser } from "src/utils";
8+
import { forking, testVip } from "src/vip-framework";
9+
10+
import vip573 from "../../vips/vip-573/bscmainnet";
11+
import COMPTROLLER_ABI from "./abi/Comptroller.json";
12+
import DIAMOND_ABI from "./abi/Diamond.json";
13+
14+
const { bscmainnet } = NETWORK_ADDRESSES;
15+
16+
const OLD_MARKET_FACET = "0x7ec871BA4248CC443a994f2febeDFB96DAe444F1";
17+
18+
const NEW_MARKET_FACET = "0x87FdF72FA2fB29Cb43f03aCa261A8DC2C613a860";
19+
20+
// Function selector for enterMarketBehalf(address,address)
21+
const ENTER_MARKET_BEHALF_SELECTOR = "0xd585c3c6";
22+
23+
// Test accounts
24+
const TEST_USER = "0x14A1c22EF6d2eF6cE33c0b018d8A34D02021e5c8";
25+
const TEST_DELEGATE = "0x9cc6f5f16498fceef4d00a350bd8f8921d304dc9";
26+
const VUSDT = "0xfD5840Cd36d94D7229439859C0112a4185BC0255";
27+
28+
forking(69628476, async () => {
29+
const provider = ethers.provider;
30+
let unitroller: Contract;
31+
32+
let marketFacetFunctionSelectors: string[];
33+
34+
before(async () => {
35+
unitroller = new ethers.Contract(bscmainnet.UNITROLLER, COMPTROLLER_ABI, provider);
36+
37+
// Get current MarketFacet function selectors
38+
marketFacetFunctionSelectors = await unitroller.facetFunctionSelectors(OLD_MARKET_FACET);
39+
});
40+
41+
describe("Pre-VIP behavior", async () => {
42+
it("MarketFacet should have old implementation", async () => {
43+
expect(await unitroller.facetFunctionSelectors(OLD_MARKET_FACET)).to.deep.equal(marketFacetFunctionSelectors);
44+
expect(await unitroller.facetFunctionSelectors(NEW_MARKET_FACET)).to.deep.equal([]);
45+
});
46+
47+
it("enterMarketBehalf function should not exist", async () => {
48+
expect(marketFacetFunctionSelectors).to.not.include(ENTER_MARKET_BEHALF_SELECTOR);
49+
});
50+
51+
it("unitroller should contain old MarketFacet address", async () => {
52+
expect(await unitroller.facetAddresses()).to.include(OLD_MARKET_FACET);
53+
expect(await unitroller.facetAddresses()).to.not.include(NEW_MARKET_FACET);
54+
});
55+
});
56+
57+
testVip("vip-573", await vip573(), {
58+
callbackAfterExecution: async (txResponse: TransactionResponse) => {
59+
await expectEvents(txResponse, [DIAMOND_ABI], ["DiamondCut"], [1]);
60+
},
61+
});
62+
63+
describe("Post-VIP behavior", async () => {
64+
it("MarketFacet function selectors should be updated for new facet address", async () => {
65+
const newMarketFacetFunctionSelectors = [ENTER_MARKET_BEHALF_SELECTOR];
66+
67+
const expectSelectors = [...marketFacetFunctionSelectors, ...newMarketFacetFunctionSelectors].sort();
68+
const updatedSelectors = [...(await unitroller.facetFunctionSelectors(NEW_MARKET_FACET))].sort();
69+
70+
expect(updatedSelectors).to.deep.equal(expectSelectors);
71+
expect(await unitroller.facetFunctionSelectors(OLD_MARKET_FACET)).to.deep.equal([]);
72+
});
73+
74+
it("unitroller should contain new MarketFacet address", async () => {
75+
expect(await unitroller.facetAddresses()).to.include(NEW_MARKET_FACET);
76+
expect(await unitroller.facetAddresses()).to.not.include(OLD_MARKET_FACET);
77+
});
78+
79+
it("enterMarketBehalf function should exist in new facet", async () => {
80+
const newFacetSelectors = await unitroller.facetFunctionSelectors(NEW_MARKET_FACET);
81+
expect(newFacetSelectors).to.include(ENTER_MARKET_BEHALF_SELECTOR);
82+
});
83+
it("should allow approved delegate to enter market on behalf of user", async () => {
84+
const user = await initMainnetUser(TEST_USER, parseEther("10000"));
85+
86+
// First, exit the market if already in it
87+
try {
88+
await unitroller.connect(user).exitMarket(VUSDT);
89+
} catch (e) {
90+
// Market might not be entered, continue
91+
}
92+
93+
// Approve delegate
94+
await unitroller.connect(user).updateDelegate(TEST_DELEGATE, true);
95+
96+
// Switch to delegate
97+
const delegate = await initMainnetUser(TEST_DELEGATE, parseEther("10000"));
98+
99+
// Check membership before
100+
const membershipBefore = await unitroller.checkMembership(TEST_USER, VUSDT);
101+
expect(membershipBefore).to.be.false;
102+
103+
await expect(await unitroller.connect(delegate).enterMarketBehalf(TEST_USER, VUSDT))
104+
.to.emit(unitroller, "MarketEntered")
105+
.withArgs(VUSDT, TEST_USER);
106+
107+
// Check membership after
108+
const membershipAfter = await unitroller.checkMembership(TEST_USER, VUSDT);
109+
expect(membershipAfter).to.be.true;
110+
});
111+
112+
it("should revert when unapproved delegate tries to enter market", async () => {
113+
const userSigner = await initMainnetUser(TEST_DELEGATE, parseEther("10000"));
114+
const comptroller = unitroller.connect(userSigner);
115+
116+
try {
117+
await comptroller.exitMarket(VUSDT);
118+
} catch (e) {
119+
// Market might not be entered, continue
120+
}
121+
122+
const delegateSigner = await initMainnetUser(TEST_USER, parseEther("10000"));
123+
const comptrollerDelegate = unitroller.connect(delegateSigner);
124+
125+
// Should revert with NotAnApprovedDelegate
126+
await expect(comptrollerDelegate.enterMarketBehalf(TEST_DELEGATE, VUSDT)).to.be.revertedWithCustomError(
127+
comptrollerDelegate,
128+
"NotAnApprovedDelegate",
129+
);
130+
});
131+
});
132+
});

simulations/vip-573/bsctestnet.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { TransactionResponse } from "@ethersproject/providers";
2+
import { expect } from "chai";
3+
import { Contract } from "ethers";
4+
import { parseEther } from "ethers/lib/utils";
5+
import { ethers } from "hardhat";
6+
import { NETWORK_ADDRESSES } from "src/networkAddresses";
7+
import { expectEvents, initMainnetUser } from "src/utils";
8+
import { forking, testVip } from "src/vip-framework";
9+
10+
import vip573 from "../../vips/vip-573/bsctestnet";
11+
import COMPTROLLER_ABI from "./abi/Comptroller.json";
12+
import DIAMOND_ABI from "./abi/Diamond.json";
13+
14+
const { bsctestnet } = NETWORK_ADDRESSES;
15+
16+
const OLD_MARKET_FACET = "0x0A7A88aB6aB40417Bd6bF1EB3907EFF06D24C2FC";
17+
18+
const NEW_MARKET_FACET = "0x8e0e15C99Ab0985cB39B2FE36532E5692730eBA9";
19+
20+
// Function selector for enterMarketBehalf(address,address)
21+
const ENTER_MARKET_BEHALF_SELECTOR = "0xd585c3c6";
22+
23+
// Test accounts
24+
const TEST_USER = "0x14A1c22EF6d2eF6cE33c0b018d8A34D02021e5c8";
25+
const TEST_DELEGATE = "0x9cc6f5f16498fceef4d00a350bd8f8921d304dc9";
26+
const VUSDT = "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A";
27+
28+
forking(73659707, async () => {
29+
const provider = ethers.provider;
30+
let unitroller: Contract;
31+
32+
let marketFacetFunctionSelectors: string[];
33+
34+
before(async () => {
35+
unitroller = new ethers.Contract(bsctestnet.UNITROLLER, COMPTROLLER_ABI, provider);
36+
37+
// Get current MarketFacet function selectors
38+
marketFacetFunctionSelectors = await unitroller.facetFunctionSelectors(OLD_MARKET_FACET);
39+
});
40+
41+
describe("Pre-VIP behavior", async () => {
42+
it("MarketFacet should have old implementation", async () => {
43+
expect(await unitroller.facetFunctionSelectors(OLD_MARKET_FACET)).to.deep.equal(marketFacetFunctionSelectors);
44+
expect(await unitroller.facetFunctionSelectors(NEW_MARKET_FACET)).to.deep.equal([]);
45+
});
46+
47+
it("enterMarketBehalf function should not exist", async () => {
48+
expect(marketFacetFunctionSelectors).to.not.include(ENTER_MARKET_BEHALF_SELECTOR);
49+
});
50+
51+
it("unitroller should contain old MarketFacet address", async () => {
52+
expect(await unitroller.facetAddresses()).to.include(OLD_MARKET_FACET);
53+
expect(await unitroller.facetAddresses()).to.not.include(NEW_MARKET_FACET);
54+
});
55+
});
56+
57+
testVip("vip-573", await vip573(), {
58+
callbackAfterExecution: async (txResponse: TransactionResponse) => {
59+
await expectEvents(txResponse, [DIAMOND_ABI], ["DiamondCut"], [1]);
60+
},
61+
});
62+
63+
describe("Post-VIP behavior", async () => {
64+
it("MarketFacet function selectors should be updated for new facet address", async () => {
65+
const newMarketFacetFunctionSelectors = [ENTER_MARKET_BEHALF_SELECTOR];
66+
67+
const expectSelectors = [...marketFacetFunctionSelectors, ...newMarketFacetFunctionSelectors].sort();
68+
const updatedSelectors = [...(await unitroller.facetFunctionSelectors(NEW_MARKET_FACET))].sort();
69+
70+
expect(updatedSelectors).to.deep.equal(expectSelectors);
71+
expect(await unitroller.facetFunctionSelectors(OLD_MARKET_FACET)).to.deep.equal([]);
72+
});
73+
74+
it("unitroller should contain new MarketFacet address", async () => {
75+
expect(await unitroller.facetAddresses()).to.include(NEW_MARKET_FACET);
76+
expect(await unitroller.facetAddresses()).to.not.include(OLD_MARKET_FACET);
77+
});
78+
79+
it("enterMarketBehalf function should exist in new facet", async () => {
80+
const newFacetSelectors = await unitroller.facetFunctionSelectors(NEW_MARKET_FACET);
81+
expect(newFacetSelectors).to.include(ENTER_MARKET_BEHALF_SELECTOR);
82+
});
83+
it("should allow approved delegate to enter market on behalf of user", async () => {
84+
const user = await initMainnetUser(TEST_USER, parseEther("10000"));
85+
86+
// First, exit the market if already in it
87+
try {
88+
await unitroller.connect(user).exitMarket(VUSDT);
89+
} catch (e) {
90+
// Market might not be entered, continue
91+
}
92+
93+
// Approve delegate
94+
await unitroller.connect(user).updateDelegate(TEST_DELEGATE, true);
95+
96+
// Switch to delegate
97+
const delegate = await initMainnetUser(TEST_DELEGATE, parseEther("10000"));
98+
99+
// Check membership before
100+
const membershipBefore = await unitroller.checkMembership(TEST_USER, VUSDT);
101+
expect(membershipBefore).to.be.false;
102+
103+
await expect(await unitroller.connect(delegate).enterMarketBehalf(TEST_USER, VUSDT))
104+
.to.emit(unitroller, "MarketEntered")
105+
.withArgs(VUSDT, TEST_USER);
106+
107+
// Check membership after
108+
const membershipAfter = await unitroller.checkMembership(TEST_USER, VUSDT);
109+
expect(membershipAfter).to.be.true;
110+
});
111+
112+
it("should revert when unapproved delegate tries to enter market", async () => {
113+
const userSigner = await initMainnetUser(TEST_DELEGATE, parseEther("10000"));
114+
const comptroller = unitroller.connect(userSigner);
115+
116+
try {
117+
await comptroller.exitMarket(VUSDT);
118+
} catch (e) {
119+
// Market might not be entered, continue
120+
}
121+
122+
const delegateSigner = await initMainnetUser(TEST_USER, parseEther("10000"));
123+
const comptrollerDelegate = unitroller.connect(delegateSigner);
124+
125+
// Should revert with NotAnApprovedDelegate
126+
await expect(comptrollerDelegate.enterMarketBehalf(TEST_DELEGATE, VUSDT)).to.be.revertedWithCustomError(
127+
comptrollerDelegate,
128+
"NotAnApprovedDelegate",
129+
);
130+
});
131+
});
132+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"cutParams": [
3+
[
4+
"0x87FdF72FA2fB29Cb43f03aCa261A8DC2C613a860",
5+
1,
6+
[
7+
"0xa76b3fda",
8+
"0x929fe9a1",
9+
"0xc2998238",
10+
"0xede4edd0",
11+
"0xb0772d0b",
12+
"0xabfceffc",
13+
"0x007e3dd2",
14+
"0xc488847b",
15+
"0xa78dc775",
16+
"0x0686dab6",
17+
"0xddbf54fd",
18+
"0x3d98a1e5",
19+
"0xcab4f84c",
20+
"0xc5b4db55",
21+
"0x89c13be0",
22+
"0xd0d13036",
23+
"0xf9682732",
24+
"0x23617585",
25+
"0xafd3783b",
26+
"0x19ef3e8b",
27+
"0xd686e9ee",
28+
"0x7b86e42c",
29+
"0x63e0d634",
30+
"0xf02fdf97",
31+
"0x0ef332ca",
32+
"0x8e8f294b",
33+
"0x3093c11e",
34+
"0xd137f36e",
35+
"0xd463654c",
36+
"0x4d99c776"
37+
]
38+
],
39+
["0x87FdF72FA2fB29Cb43f03aCa261A8DC2C613a860", 0, ["0xd585c3c6"]]
40+
]
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"cutParams": [
3+
[
4+
"0x8e0e15C99Ab0985cB39B2FE36532E5692730eBA9",
5+
1,
6+
[
7+
"0xa76b3fda",
8+
"0x929fe9a1",
9+
"0xc2998238",
10+
"0xede4edd0",
11+
"0xb0772d0b",
12+
"0xabfceffc",
13+
"0x007e3dd2",
14+
"0xc488847b",
15+
"0xa78dc775",
16+
"0x0686dab6",
17+
"0xddbf54fd",
18+
"0x3d98a1e5",
19+
"0xcab4f84c",
20+
"0xc5b4db55",
21+
"0x89c13be0",
22+
"0xd0d13036",
23+
"0xf9682732",
24+
"0x23617585",
25+
"0xafd3783b",
26+
"0x19ef3e8b",
27+
"0xd686e9ee",
28+
"0x7b86e42c",
29+
"0x63e0d634",
30+
"0xf02fdf97",
31+
"0x0ef332ca",
32+
"0x8e8f294b",
33+
"0x3093c11e",
34+
"0xd137f36e",
35+
"0xd463654c",
36+
"0x4d99c776"
37+
]
38+
],
39+
["0x8e0e15C99Ab0985cB39B2FE36532E5692730eBA9", 0, ["0xd585c3c6"]]
40+
]
41+
}

vips/vip-573/bscmainnet.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { NETWORK_ADDRESSES } from "src/networkAddresses";
2+
import { ProposalType } from "src/types";
3+
import { makeProposal } from "src/utils";
4+
5+
import { cutParams as params } from "../../simulations/vip-573/utils/cut-params-bscmainnet.json";
6+
7+
const { bscmainnet } = NETWORK_ADDRESSES;
8+
9+
export const cutParams = params;
10+
11+
export const vip573 = () => {
12+
const meta = {
13+
version: "v2",
14+
title: "VIP-573 [BNB Chain] Add enterMarketBehalf support to Comptroller",
15+
description: `#### Summary
16+
17+
If passed, this VIP will upgrade the MarketFacet of the core pool Comptroller on BNB Chain Mainnet to add support for the \`enterMarketBehalf\` function, allowing approved delegates to enter markets on behalf of users.
18+
19+
#### Description`,
20+
forDescription: "Execute this proposal",
21+
againstDescription: "Do not execute this proposal",
22+
abstainDescription: "Indifferent to execution",
23+
};
24+
25+
return makeProposal(
26+
[
27+
{
28+
target: bscmainnet.UNITROLLER,
29+
signature: "diamondCut((address,uint8,bytes4[])[])",
30+
params: [cutParams],
31+
},
32+
],
33+
meta,
34+
ProposalType.REGULAR,
35+
);
36+
};
37+
38+
export default vip573;

0 commit comments

Comments
 (0)