Skip to content

Commit 74774a6

Browse files
authored
Merge pull request #287 from solidstate-network/receive
Add `receive` function to `Proxy`
2 parents 619f183 + e34353b commit 74774a6

11 files changed

+67
-24
lines changed

contracts/proxy/IProxy.sol

+2
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ import { _IProxy } from './_IProxy.sol';
66

77
interface IProxy is _IProxy {
88
fallback() external payable;
9+
10+
receive() external payable;
911
}

contracts/proxy/Proxy.sol

+4
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@ abstract contract Proxy is IProxy, _Proxy {
1616
fallback() external payable {
1717
_fallback();
1818
}
19+
20+
receive() external payable {
21+
_receive();
22+
}
1923
}

contracts/proxy/_Proxy.sol

+7
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,11 @@ abstract contract _Proxy is _IProxy {
6868

6969
revert Proxy__ImplementationIsNotContract();
7070
}
71+
72+
/**
73+
* @notice received ether is forwarded to the fallback function
74+
*/
75+
function _receive() internal virtual {
76+
_fallback();
77+
}
7178
}

contracts/proxy/diamond/ISolidstateDiamondProxy.sol

+1-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,4 @@ interface ISolidstateDiamondProxy is
1616
IDiamondProxyReadable,
1717
IDiamondProxyWritable,
1818
ISafeOwnable
19-
{
20-
receive() external payable;
21-
}
19+
{}

contracts/proxy/diamond/SolidstateDiamondProxy.sol

-2
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ abstract contract SolidstateDiamondProxy is
9999
_setOwner(msg.sender);
100100
}
101101

102-
receive() external payable {}
103-
104102
function _transferOwnership(
105103
address account
106104
)

spec/proxy/Proxy.behavior.ts

+14
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,19 @@ export function describeBehaviorOfProxy(
3737
).not.to.be.reverted;
3838
});
3939
});
40+
41+
describe('receive()', () => {
42+
it('forwards value to implementation via delegatecall', async () => {
43+
// TODO: receive tests pass because hardhat-exposed functions used as implementations are payable
44+
const [signer] = await ethers.getSigners();
45+
46+
await expect(
47+
signer.sendTransaction({
48+
to: await instance.getAddress(),
49+
value: 1n,
50+
}),
51+
).not.to.be.reverted;
52+
});
53+
});
4054
});
4155
}

spec/proxy/diamond/DiamondProxy.behavior.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describeFilter } from '@solidstate/library';
2-
import { ProxyBehaviorArgs } from '@solidstate/spec';
2+
import { describeBehaviorOfProxy, ProxyBehaviorArgs } from '@solidstate/spec';
33
import { IDiamondProxy } from '@solidstate/typechain-types';
44
import { expect } from 'chai';
55
import { ethers } from 'hardhat';
@@ -20,6 +20,8 @@ export function describeBehaviorOfDiamondProxy(
2020
instance = await deploy();
2121
});
2222

23+
describeBehaviorOfProxy(deploy, args, skips);
24+
2325
describe('fallback()', () => {
2426
it('forwards data with matching selector call to facet', async () => {
2527
expect(instance.interface.hasFunction(args.implementationFunction)).to
@@ -55,5 +57,9 @@ export function describeBehaviorOfDiamondProxy(
5557
});
5658
});
5759
});
60+
61+
describe('receive()', () => {
62+
it('todo');
63+
});
5864
});
5965
}

spec/proxy/diamond/SolidstateDiamondProxy.behavior.ts

-12
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,6 @@ export function describeBehaviorOfSolidstateDiamondProxy(
7878

7979
describeBehaviorOfSafeOwnable(deploy, args, skips);
8080

81-
describe('receive()', () => {
82-
it('accepts ether transfer', async () => {
83-
const [signer] = await ethers.getSigners();
84-
const value = 1;
85-
const to = await instance.getAddress();
86-
87-
await expect(() =>
88-
signer.sendTransaction({ to, value }),
89-
).to.changeEtherBalance(instance, value);
90-
});
91-
});
92-
9381
describe('#diamondCut((address,enum,bytes4[])[],address,bytes)', () => {
9482
const selectors: string[] = [];
9583
const abi: string[] = [];

spec/proxy/diamond/fallback/DiamondProxyFallback.behavior.ts

+28-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,36 @@ export function describeBehaviorOfDiamondProxyFallback(
3131
nonOwner = await args.getNonOwner();
3232
});
3333

34-
describeBehaviorOfDiamondProxy(async () => instance, args, skips);
34+
describeBehaviorOfDiamondProxy(async () => instance, args, [
35+
'receive()',
36+
...(skips ?? []),
37+
]);
3538

3639
describe('fallback()', () => {
37-
it('forwards data without matching selector to fallback contract');
40+
it('forwards data without matching selector to fallback contract', async () => {
41+
await expect(
42+
owner.sendTransaction({
43+
to: await instance.getAddress(),
44+
}),
45+
).to.be.revertedWithCustomError(
46+
instance,
47+
'Proxy__ImplementationIsNotContract',
48+
);
49+
});
50+
});
51+
52+
describe('receive()', () => {
53+
it('forwards value to fallback contract', async () => {
54+
await expect(
55+
owner.sendTransaction({
56+
to: await instance.getAddress(),
57+
value: 1n,
58+
}),
59+
).to.be.revertedWithCustomError(
60+
instance,
61+
'Proxy__ImplementationIsNotContract',
62+
);
63+
});
3864
});
3965

4066
describe('#getFallbackAddress()', () => {

test/proxy/diamond/SolidstateDiamondProxy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ describe('SolidstateDiamondProxy', () => {
5454
fallbackAddress: ethers.ZeroAddress,
5555
immutableSelectors,
5656
},
57-
['fallback()'],
57+
['fallback()', 'receive()'],
5858
);
5959
});

test/proxy/upgradeable/UpgradeableProxy.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
22
import { describeBehaviorOfUpgradeableProxy } from '@solidstate/spec';
33
import {
4-
$Ownable__factory,
4+
$SafeOwnable__factory,
55
$UpgradeableProxy,
66
$UpgradeableProxy__factory,
77
} from '@solidstate/typechain-types';
@@ -20,7 +20,7 @@ describe('UpgradeableProxy', () => {
2020
beforeEach(async () => {
2121
const [deployer] = await ethers.getSigners();
2222

23-
const implementationInstance = await new $Ownable__factory(
23+
const implementationInstance = await new $SafeOwnable__factory(
2424
deployer,
2525
).deploy();
2626

@@ -35,7 +35,7 @@ describe('UpgradeableProxy', () => {
3535
describeBehaviorOfUpgradeableProxy(async () => instance, {
3636
getOwner: async () => owner,
3737
getNonOwner: async () => nonOwner,
38-
implementationFunction: 'owner()',
38+
implementationFunction: 'nomineeOwner()',
3939
implementationFunctionArgs: [],
4040
});
4141

0 commit comments

Comments
 (0)