Skip to content

Commit de708ba

Browse files
authored
Merge pull request #2207 from opentensor/get_proxies_in_precompile
add getProxies in precompile
2 parents 133d8d9 + 4194c75 commit de708ba

File tree

6 files changed

+339
-20
lines changed

6 files changed

+339
-20
lines changed

common/src/lib.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,37 @@ impl TryFrom<u8> for ProxyType {
184184
14 => Ok(Self::SudoUncheckedSetCode),
185185
15 => Ok(Self::SwapHotkey),
186186
16 => Ok(Self::SubnetLeaseBeneficiary),
187+
17 => Ok(Self::RootClaim),
187188
_ => Err(()),
188189
}
189190
}
190191
}
191192

193+
impl From<ProxyType> for u8 {
194+
fn from(proxy_type: ProxyType) -> Self {
195+
match proxy_type {
196+
ProxyType::Any => 0,
197+
ProxyType::Owner => 1,
198+
ProxyType::NonCritical => 2,
199+
ProxyType::NonTransfer => 3,
200+
ProxyType::Senate => 4,
201+
ProxyType::NonFungible => 5,
202+
ProxyType::Triumvirate => 6,
203+
ProxyType::Governance => 7,
204+
ProxyType::Staking => 8,
205+
ProxyType::Registration => 9,
206+
ProxyType::Transfer => 10,
207+
ProxyType::SmallTransfer => 11,
208+
ProxyType::RootWeights => 12,
209+
ProxyType::ChildKeys => 13,
210+
ProxyType::SudoUncheckedSetCode => 14,
211+
ProxyType::SwapHotkey => 15,
212+
ProxyType::SubnetLeaseBeneficiary => 16,
213+
ProxyType::RootClaim => 17,
214+
}
215+
}
216+
}
217+
192218
impl Default for ProxyType {
193219
// allow all Calls; required to be most permissive
194220
fn default() -> Self {

contract-tests/src/contracts/proxy.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,5 +144,41 @@ export const IProxyABI = [
144144
"outputs": [],
145145
"stateMutability": "nonpayable",
146146
"type": "function"
147+
},
148+
{
149+
"inputs": [
150+
{
151+
"internalType": "bytes32",
152+
"name": "account",
153+
"type": "bytes32"
154+
}
155+
],
156+
"name": "getProxies",
157+
"outputs": [
158+
{
159+
"components": [
160+
{
161+
"internalType": "bytes32",
162+
"name": "delegate",
163+
"type": "bytes32"
164+
},
165+
{
166+
"internalType": "uint256",
167+
"name": "proxy_type",
168+
"type": "uint256"
169+
},
170+
{
171+
"internalType": "uint256",
172+
"name": "delay",
173+
"type": "uint256"
174+
}
175+
],
176+
"internalType": "struct IProxy.ProxyInfo[]",
177+
"name": "",
178+
"type": "tuple[]"
179+
}
180+
],
181+
"stateMutability": "view",
182+
"type": "function"
147183
}
148184
];

contract-tests/test/pure-proxy.precompile.test.ts

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ async function getProxies(api: TypedApi<typeof devnet>, address: string) {
4646

4747
describe("Test pure proxy precompile", () => {
4848
const evmWallet = generateRandomEthersWallet();
49+
// only used for edge case and normal proxy
4950
const evmWallet2 = generateRandomEthersWallet();
5051
const evmWallet3 = generateRandomEthersWallet();
52+
const evmWallet4 = generateRandomEthersWallet();
5153
const receiver = getRandomSubstrateKeypair();
5254

5355
let api: TypedApi<typeof devnet>
@@ -61,6 +63,7 @@ describe("Test pure proxy precompile", () => {
6163
await forceSetBalanceToEthAddress(api, evmWallet.address)
6264
await forceSetBalanceToEthAddress(api, evmWallet2.address)
6365
await forceSetBalanceToEthAddress(api, evmWallet3.address)
66+
await forceSetBalanceToEthAddress(api, evmWallet4.address)
6467
})
6568

6669
it("Call createPureProxy, then use proxy to call transfer", async () => {
@@ -130,34 +133,78 @@ describe("Test pure proxy precompile", () => {
130133
const proxies = await api.query.Proxy.Proxies.getValue(convertH160ToSS58(evmWallet2.address))
131134
const contract = new ethers.Contract(IPROXY_ADDRESS, IProxyABI, evmWallet2)
132135

136+
const proxiesFromContract = await contract.getProxies(convertH160ToPublicKey(evmWallet2.address))
137+
assert.equal(proxiesFromContract.length, proxies[0].length, "proxies length should be equal")
138+
133139
const type = 0;
134140
const delay = 0;
135141

136142
const tx = await contract.addProxy(convertH160ToPublicKey(evmWallet3.address), type, delay)
137143
await tx.wait()
138144

145+
const proxiesAfterAdd = await api.query.Proxy.Proxies.getValue(convertH160ToSS58(evmWallet2.address))
146+
const proxiesList = proxiesAfterAdd[0].map(proxy => proxy.delegate)
139147

140-
const proxiesAfterAdd = await await api.query.Proxy.Proxies.getValue(convertH160ToSS58(evmWallet2.address))
148+
const proxiesFromContractAfterAdd = await contract.getProxies(convertH160ToPublicKey(evmWallet2.address))
141149

142-
const length = proxiesAfterAdd[0].length
143-
assert.equal(length, proxies[0].length + 1, "proxy should be set")
144-
const proxy = proxiesAfterAdd[0][proxiesAfterAdd[0].length - 1]
150+
assert.equal(proxiesFromContractAfterAdd.length, proxiesList.length, "proxy length should be equal")
145151

146-
assert.equal(proxy.delegate, convertH160ToSS58(evmWallet3.address), "proxy should be set")
152+
for (let index = 0; index < proxiesFromContractAfterAdd.length; index++) {
153+
const proxyInfo = proxiesFromContractAfterAdd[index]
154+
let proxySs58 = convertPublicKeyToSs58(proxyInfo[0])
155+
assert.ok(proxiesList.includes(proxySs58), "proxy should be set")
156+
if (index === proxiesFromContractAfterAdd.length - 1) {
157+
assert.equal(Number(proxyInfo[1]), type, "proxy_type should match")
158+
assert.equal(Number(proxyInfo[2]), delay, "delay should match")
159+
}
160+
}
147161

162+
assert.equal(proxiesList.length, proxies[0].length + 1, "proxy should be set")
163+
const proxy = proxiesList[proxiesList.length - 1]
148164

165+
assert.equal(proxy, convertH160ToSS58(evmWallet3.address), "proxy should be set")
149166
const balance = (await api.query.System.Account.getValue(convertPublicKeyToSs58(receiver.publicKey))).data.free
150-
151167
const amount = 1000000000;
152168

153169
const contract2 = new ethers.Contract(IPROXY_ADDRESS, IProxyABI, evmWallet3)
154-
155-
156170
const callCode = await getTransferCallCode(api, receiver, amount)
157171
const tx2 = await contract2.proxyCall(convertH160ToPublicKey(evmWallet2.address), [type], callCode)
158172
await tx2.wait()
159173

160174
const balanceAfter = (await api.query.System.Account.getValue(convertPublicKeyToSs58(receiver.publicKey))).data.free
161175
assert.equal(balanceAfter, balance + BigInt(amount), "balance should be increased")
162176
})
177+
178+
it("Call addProxy many times, then check getProxies is correct", async () => {
179+
const proxies = await api.query.Proxy.Proxies.getValue(convertH160ToSS58(evmWallet4.address))
180+
const contract = new ethers.Contract(IPROXY_ADDRESS, IProxyABI, evmWallet4)
181+
assert.equal(proxies[0].length, 0, "proxies length should be 0")
182+
183+
const proxiesFromContract = await contract.getProxies(convertH160ToPublicKey(evmWallet4.address))
184+
assert.equal(proxiesFromContract.length, proxies[0].length, "proxies length should be equal")
185+
186+
const type = 1;
187+
const delay = 2;
188+
189+
for (let i = 0; i < 5; i++) {
190+
const evmWallet = generateRandomEthersWallet()
191+
const tx = await contract.addProxy(convertH160ToPublicKey(evmWallet.address), type, delay)
192+
await tx.wait()
193+
}
194+
195+
const proxiesAfterAdd = await await api.query.Proxy.Proxies.getValue(convertH160ToSS58(evmWallet4.address))
196+
const proxiesList = proxiesAfterAdd[0].map(proxy => proxy.delegate)
197+
198+
const proxiesFromContractAfterAdd = await contract.getProxies(convertH160ToPublicKey(evmWallet4.address))
199+
200+
assert.equal(proxiesFromContractAfterAdd.length, proxiesList.length, "proxy length should be equal")
201+
202+
for (let index = 0; index < proxiesFromContractAfterAdd.length; index++) {
203+
const proxyInfo = proxiesFromContractAfterAdd[index]
204+
let proxySs58 = convertPublicKeyToSs58(proxyInfo[0])
205+
assert.ok(proxiesList.includes(proxySs58), "proxy should be set")
206+
assert.equal(Number(proxyInfo[1]), type, "proxy_type should match")
207+
assert.equal(Number(proxyInfo[2]), delay, "delay should match")
208+
}
209+
})
163210
});

precompiles/src/proxy.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ use frame_system::RawOrigin;
99
use pallet_evm::{AddressMapping, PrecompileHandle};
1010
use pallet_subtensor_proxy as pallet_proxy;
1111
use precompile_utils::EvmResult;
12-
use sp_core::H256;
12+
use sp_core::{H256, U256};
1313
use sp_runtime::{
1414
codec::DecodeLimit,
1515
traits::{Dispatchable, StaticLookup},
1616
};
1717
use sp_std::boxed::Box;
18+
use sp_std::convert::{TryFrom, TryInto};
19+
use sp_std::vec;
1820
use sp_std::vec::Vec;
1921
use subtensor_runtime_common::ProxyType;
2022
pub struct ProxyPrecompile<R>(PhantomData<R>);
@@ -239,4 +241,30 @@ where
239241

240242
handle.try_dispatch_runtime_call::<R, _>(call, RawOrigin::Signed(account_id))
241243
}
244+
245+
#[precompile::public("getProxies(bytes32)")]
246+
#[precompile::view]
247+
pub fn get_proxies(
248+
_handle: &mut impl PrecompileHandle,
249+
account_id: H256,
250+
) -> EvmResult<Vec<(H256, U256, U256)>> {
251+
let account_id = R::AccountId::from(account_id.0.into());
252+
253+
let proxies = pallet_proxy::pallet::Pallet::<R>::proxies(account_id);
254+
let mut result: Vec<(H256, U256, U256)> = vec![];
255+
for proxy in proxies.0 {
256+
let delegate: [u8; 32] = proxy.delegate.into();
257+
let proxy_type: u8 = proxy.proxy_type.into();
258+
let delay: u32 = proxy
259+
.delay
260+
.try_into()
261+
.map_err(|_| PrecompileFailure::Error {
262+
exit_status: ExitError::Other("Invalid delay".into()),
263+
})?;
264+
265+
result.push((delegate.into(), proxy_type.into(), delay.into()));
266+
}
267+
268+
Ok(result)
269+
}
242270
}

precompiles/src/solidity/proxy.abi

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
[
2+
{
3+
"type": "function",
4+
"name": "createPureProxy",
5+
"inputs": [
6+
{
7+
"name": "proxy_type",
8+
"type": "uint8",
9+
"internalType": "uint8"
10+
},
11+
{
12+
"name": "delay",
13+
"type": "uint32",
14+
"internalType": "uint32"
15+
},
16+
{
17+
"name": "index",
18+
"type": "uint16",
19+
"internalType": "uint16"
20+
}
21+
],
22+
"outputs": [],
23+
"stateMutability": "nonpayable"
24+
},
25+
{
26+
"type": "function",
27+
"name": "proxyCall",
28+
"inputs": [
29+
{
30+
"name": "real",
31+
"type": "bytes32",
32+
"internalType": "bytes32"
33+
},
34+
{
35+
"name": "force_proxy_type",
36+
"type": "uint8[]",
37+
"internalType": "uint8[]"
38+
},
39+
{
40+
"name": "call",
41+
"type": "bytes",
42+
"internalType": "bytes"
43+
}
44+
],
45+
"outputs": [],
46+
"stateMutability": "nonpayable"
47+
},
48+
{
49+
"type": "function",
50+
"name": "killPureProxy",
51+
"inputs": [
52+
{
53+
"name": "spawner",
54+
"type": "bytes32",
55+
"internalType": "bytes32"
56+
},
57+
{
58+
"name": "proxy_type",
59+
"type": "uint8",
60+
"internalType": "uint8"
61+
},
62+
{
63+
"name": "index",
64+
"type": "uint16",
65+
"internalType": "uint16"
66+
},
67+
{
68+
"name": "height",
69+
"type": "uint16",
70+
"internalType": "uint16"
71+
},
72+
{
73+
"name": "ext_index",
74+
"type": "uint32",
75+
"internalType": "uint32"
76+
}
77+
],
78+
"outputs": [],
79+
"stateMutability": "nonpayable"
80+
},
81+
{
82+
"type": "function",
83+
"name": "addProxy",
84+
"inputs": [
85+
{
86+
"name": "delegate",
87+
"type": "bytes32",
88+
"internalType": "bytes32"
89+
},
90+
{
91+
"name": "proxy_type",
92+
"type": "uint8",
93+
"internalType": "uint8"
94+
},
95+
{
96+
"name": "delay",
97+
"type": "uint32",
98+
"internalType": "uint32"
99+
}
100+
],
101+
"outputs": [],
102+
"stateMutability": "nonpayable"
103+
},
104+
{
105+
"type": "function",
106+
"name": "removeProxy",
107+
"inputs": [
108+
{
109+
"name": "delegate",
110+
"type": "bytes32",
111+
"internalType": "bytes32"
112+
},
113+
{
114+
"name": "proxy_type",
115+
"type": "uint8",
116+
"internalType": "uint8"
117+
},
118+
{
119+
"name": "delay",
120+
"type": "uint32",
121+
"internalType": "uint32"
122+
}
123+
],
124+
"outputs": [],
125+
"stateMutability": "nonpayable"
126+
},
127+
{
128+
"type": "function",
129+
"name": "removeProxies",
130+
"inputs": [],
131+
"outputs": [],
132+
"stateMutability": "nonpayable"
133+
},
134+
{
135+
"type": "function",
136+
"name": "pokeDeposit",
137+
"inputs": [],
138+
"outputs": [],
139+
"stateMutability": "nonpayable"
140+
},
141+
{
142+
"type": "function",
143+
"name": "getProxies",
144+
"inputs": [
145+
{
146+
"name": "account",
147+
"type": "bytes32",
148+
"internalType": "bytes32"
149+
}
150+
],
151+
"outputs": [
152+
{
153+
"name": "",
154+
"type": "bytes32[]",
155+
"internalType": "bytes32[]"
156+
}
157+
],
158+
"stateMutability": "view"
159+
}
160+
]

0 commit comments

Comments
 (0)