@gearbox-protocol/sdk 14.12.0-next.50 → 14.12.0-next.51
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/dist/cjs/dev/claimDSToken.js +10 -122
- package/dist/cjs/dev/index.js +2 -0
- package/dist/cjs/dev/kycUtils.js +351 -0
- package/dist/esm/dev/claimDSToken.js +9 -123
- package/dist/esm/dev/index.js +1 -0
- package/dist/esm/dev/kycUtils.js +332 -0
- package/dist/types/dev/claimDSToken.d.ts +2 -3
- package/dist/types/dev/index.d.ts +1 -0
- package/dist/types/dev/kycUtils.d.ts +124 -0
- package/package.json +1 -1
|
@@ -19,129 +19,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var claimDSToken_exports = {};
|
|
20
20
|
__export(claimDSToken_exports, {
|
|
21
21
|
claimDSToken: () => claimDSToken,
|
|
22
|
-
claimDSTokens: () => claimDSTokens
|
|
23
|
-
registerInvestor: () => registerInvestor
|
|
22
|
+
claimDSTokens: () => claimDSTokens
|
|
24
23
|
});
|
|
25
24
|
module.exports = __toCommonJS(claimDSToken_exports);
|
|
26
25
|
var import_viem = require("viem");
|
|
27
26
|
var import_accounts = require("viem/accounts");
|
|
28
|
-
var import_iDSRegistryService = require("../abi/rwa/iDSRegistryService.js");
|
|
29
27
|
var import_iDSToken = require("../abi/rwa/iDSToken.js");
|
|
30
28
|
var import_sdk = require("../sdk/index.js");
|
|
31
|
-
|
|
32
|
-
const hash = await anvil.writeContract(params);
|
|
33
|
-
await anvil.mine({ blocks: 1 });
|
|
34
|
-
await anvil.waitForTransactionReceipt({
|
|
35
|
-
hash,
|
|
36
|
-
pollingInterval: 100
|
|
37
|
-
});
|
|
38
|
-
return hash;
|
|
39
|
-
}
|
|
40
|
-
async function registerInvestor(props) {
|
|
41
|
-
const { claimer, anvil, token, adminPrivateKey, logger } = props;
|
|
42
|
-
const account = (0, import_accounts.privateKeyToAccount)(adminPrivateKey);
|
|
43
|
-
const registryServiceId = await anvil.readContract({
|
|
44
|
-
address: token,
|
|
45
|
-
abi: import_iDSToken.iDSTokenAbi,
|
|
46
|
-
functionName: "REGISTRY_SERVICE"
|
|
47
|
-
});
|
|
48
|
-
const registryService = await anvil.readContract({
|
|
49
|
-
address: token,
|
|
50
|
-
abi: import_iDSToken.iDSTokenAbi,
|
|
51
|
-
functionName: "getDSService",
|
|
52
|
-
args: [registryServiceId]
|
|
53
|
-
});
|
|
54
|
-
logger?.debug(`Registry service: ${registryService} (${registryServiceId})`);
|
|
55
|
-
const [isRegistered, ACCREDITED, APPROVED] = await anvil.multicall({
|
|
56
|
-
contracts: [
|
|
57
|
-
{
|
|
58
|
-
address: registryService,
|
|
59
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
60
|
-
functionName: "isWallet",
|
|
61
|
-
args: [claimer]
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
address: registryService,
|
|
65
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
66
|
-
functionName: "ACCREDITED",
|
|
67
|
-
args: []
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
address: registryService,
|
|
71
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
72
|
-
functionName: "APPROVED",
|
|
73
|
-
args: []
|
|
74
|
-
}
|
|
75
|
-
],
|
|
76
|
-
allowFailure: false
|
|
77
|
-
});
|
|
78
|
-
if (!isRegistered) {
|
|
79
|
-
logger?.debug(
|
|
80
|
-
`Claimer ${claimer} is not a registered wallet, registering...`
|
|
81
|
-
);
|
|
82
|
-
const investorId = `investor-${claimer.toLowerCase()}`;
|
|
83
|
-
const investorExists = await anvil.readContract({
|
|
84
|
-
address: registryService,
|
|
85
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
86
|
-
functionName: "isInvestor",
|
|
87
|
-
args: [investorId]
|
|
88
|
-
});
|
|
89
|
-
if (!investorExists) {
|
|
90
|
-
await writeAndWait(anvil, {
|
|
91
|
-
account,
|
|
92
|
-
chain: anvil.chain,
|
|
93
|
-
address: registryService,
|
|
94
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
95
|
-
functionName: "registerInvestor",
|
|
96
|
-
args: [investorId, investorId]
|
|
97
|
-
});
|
|
98
|
-
logger?.debug(`Registered investor "${investorId}"`);
|
|
99
|
-
}
|
|
100
|
-
await writeAndWait(anvil, {
|
|
101
|
-
account,
|
|
102
|
-
chain: anvil.chain,
|
|
103
|
-
address: registryService,
|
|
104
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
105
|
-
functionName: "addWallet",
|
|
106
|
-
args: [claimer, investorId]
|
|
107
|
-
});
|
|
108
|
-
logger?.debug(`Added wallet ${claimer} for investor "${investorId}"`);
|
|
109
|
-
try {
|
|
110
|
-
await writeAndWait(anvil, {
|
|
111
|
-
account,
|
|
112
|
-
chain: anvil.chain,
|
|
113
|
-
address: registryService,
|
|
114
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
115
|
-
functionName: "setCountry",
|
|
116
|
-
args: [investorId, "US"]
|
|
117
|
-
});
|
|
118
|
-
logger?.debug(`Set country for investor "${investorId}" to "US"`);
|
|
119
|
-
await writeAndWait(anvil, {
|
|
120
|
-
account,
|
|
121
|
-
chain: anvil.chain,
|
|
122
|
-
address: registryService,
|
|
123
|
-
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
124
|
-
functionName: "setAttribute",
|
|
125
|
-
args: [
|
|
126
|
-
investorId,
|
|
127
|
-
ACCREDITED,
|
|
128
|
-
BigInt(APPROVED),
|
|
129
|
-
import_sdk.MAX_UINT256,
|
|
130
|
-
"fake proof"
|
|
131
|
-
]
|
|
132
|
-
});
|
|
133
|
-
logger?.debug(`Set attributes for investor "${investorId}"`);
|
|
134
|
-
} catch (e) {
|
|
135
|
-
logger?.error(e);
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
logger?.debug(`Claimer ${claimer} is already a registered wallet`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
29
|
+
var import_kycUtils = require("./kycUtils.js");
|
|
141
30
|
async function claimDSToken(props) {
|
|
142
31
|
const {
|
|
143
32
|
anvil,
|
|
144
|
-
|
|
33
|
+
investor,
|
|
145
34
|
adminPrivateKey,
|
|
146
35
|
token,
|
|
147
36
|
marketConfigurators,
|
|
@@ -173,25 +62,25 @@ async function claimDSToken(props) {
|
|
|
173
62
|
throw new Error(`No market found for token ${token}`);
|
|
174
63
|
}
|
|
175
64
|
logger?.debug(`${usdAmountProp} USD === ${amount} ${symbol}`);
|
|
176
|
-
await
|
|
177
|
-
logger?.debug(`Issuing ${amount} tokens to ${
|
|
178
|
-
const mintHash = await writeAndWait(anvil, {
|
|
65
|
+
await (0, import_kycUtils.registerSecuritizeInvestor)({ ...props, logger });
|
|
66
|
+
logger?.debug(`Issuing ${amount} tokens to ${investor}...`);
|
|
67
|
+
const mintHash = await (0, import_kycUtils.writeAndWait)(anvil, {
|
|
179
68
|
account,
|
|
180
69
|
chain: anvil.chain,
|
|
181
70
|
address: token,
|
|
182
71
|
abi: import_iDSToken.iDSTokenAbi,
|
|
183
72
|
functionName: "issueTokens",
|
|
184
|
-
args: [
|
|
73
|
+
args: [investor, amount]
|
|
185
74
|
});
|
|
186
75
|
logger?.debug(`Done! tx: ${mintHash}`);
|
|
187
76
|
const balance = await anvil.readContract({
|
|
188
77
|
address: token,
|
|
189
78
|
abi: import_viem.erc20Abi,
|
|
190
79
|
functionName: "balanceOf",
|
|
191
|
-
args: [
|
|
80
|
+
args: [investor]
|
|
192
81
|
});
|
|
193
82
|
logger?.debug(
|
|
194
|
-
`Balance of ${
|
|
83
|
+
`Balance of ${investor}: ${sdk.tokensMeta.formatBN(token, balance)}`
|
|
195
84
|
);
|
|
196
85
|
}
|
|
197
86
|
async function claimDSTokens(props) {
|
|
@@ -203,6 +92,5 @@ async function claimDSTokens(props) {
|
|
|
203
92
|
// Annotate the CommonJS export names for ESM import in node:
|
|
204
93
|
0 && (module.exports = {
|
|
205
94
|
claimDSToken,
|
|
206
|
-
claimDSTokens
|
|
207
|
-
registerInvestor
|
|
95
|
+
claimDSTokens
|
|
208
96
|
});
|
package/dist/cjs/dev/index.js
CHANGED
|
@@ -35,6 +35,7 @@ __reExport(dev_exports, require("./EthCallSpy.js"), module.exports);
|
|
|
35
35
|
__reExport(dev_exports, require("./isOutOfSyncError.js"), module.exports);
|
|
36
36
|
__reExport(dev_exports, require("./isRateLimitError.js"), module.exports);
|
|
37
37
|
__reExport(dev_exports, require("./isTransientError.js"), module.exports);
|
|
38
|
+
__reExport(dev_exports, require("./kycUtils.js"), module.exports);
|
|
38
39
|
var import_logSplitterTransport = require("./logSplitterTransport.js");
|
|
39
40
|
__reExport(dev_exports, require("./ltUtils.js"), module.exports);
|
|
40
41
|
__reExport(dev_exports, require("./migrateFaucet.js"), module.exports);
|
|
@@ -63,6 +64,7 @@ __reExport(dev_exports, require("./withdrawalUtils.js"), module.exports);
|
|
|
63
64
|
...require("./isOutOfSyncError.js"),
|
|
64
65
|
...require("./isRateLimitError.js"),
|
|
65
66
|
...require("./isTransientError.js"),
|
|
67
|
+
...require("./kycUtils.js"),
|
|
66
68
|
...require("./ltUtils.js"),
|
|
67
69
|
...require("./migrateFaucet.js"),
|
|
68
70
|
...require("./mint/index.js"),
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var kycUtils_exports = {};
|
|
20
|
+
__export(kycUtils_exports, {
|
|
21
|
+
greenlistMidasGateway: () => greenlistMidasGateway,
|
|
22
|
+
registerMidasInvestor: () => registerMidasInvestor,
|
|
23
|
+
registerRWAInvestor: () => registerRWAInvestor,
|
|
24
|
+
registerSecuritizeInvestor: () => registerSecuritizeInvestor,
|
|
25
|
+
writeAndWait: () => writeAndWait
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(kycUtils_exports);
|
|
28
|
+
var import_viem = require("viem");
|
|
29
|
+
var import_accounts = require("viem/accounts");
|
|
30
|
+
var import_iDSRegistryService = require("../abi/rwa/iDSRegistryService.js");
|
|
31
|
+
var import_iDSToken = require("../abi/rwa/iDSToken.js");
|
|
32
|
+
var import_sdk = require("../sdk/index.js");
|
|
33
|
+
var import_withdrawalAbi = require("./withdrawalAbi.js");
|
|
34
|
+
async function writeAndWait(anvil, params) {
|
|
35
|
+
const hash = await anvil.writeContract(params);
|
|
36
|
+
await anvil.mine({ blocks: 1 });
|
|
37
|
+
await anvil.waitForTransactionReceipt({
|
|
38
|
+
hash,
|
|
39
|
+
pollingInterval: 100
|
|
40
|
+
});
|
|
41
|
+
return hash;
|
|
42
|
+
}
|
|
43
|
+
async function registerSecuritizeInvestor(props) {
|
|
44
|
+
const { investor, anvil, token, adminPrivateKey, logger } = props;
|
|
45
|
+
const account = (0, import_accounts.privateKeyToAccount)(adminPrivateKey);
|
|
46
|
+
const registryServiceId = await anvil.readContract({
|
|
47
|
+
address: token,
|
|
48
|
+
abi: import_iDSToken.iDSTokenAbi,
|
|
49
|
+
functionName: "REGISTRY_SERVICE"
|
|
50
|
+
});
|
|
51
|
+
const registryService = await anvil.readContract({
|
|
52
|
+
address: token,
|
|
53
|
+
abi: import_iDSToken.iDSTokenAbi,
|
|
54
|
+
functionName: "getDSService",
|
|
55
|
+
args: [registryServiceId]
|
|
56
|
+
});
|
|
57
|
+
logger?.debug(`Registry service: ${registryService} (${registryServiceId})`);
|
|
58
|
+
const [isRegistered, ACCREDITED, APPROVED] = await anvil.multicall({
|
|
59
|
+
contracts: [
|
|
60
|
+
{
|
|
61
|
+
address: registryService,
|
|
62
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
63
|
+
functionName: "isWallet",
|
|
64
|
+
args: [investor]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
address: registryService,
|
|
68
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
69
|
+
functionName: "ACCREDITED",
|
|
70
|
+
args: []
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
address: registryService,
|
|
74
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
75
|
+
functionName: "APPROVED",
|
|
76
|
+
args: []
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
allowFailure: false
|
|
80
|
+
});
|
|
81
|
+
if (!isRegistered) {
|
|
82
|
+
logger?.debug(
|
|
83
|
+
`Investor ${investor} is not a registered wallet, registering...`
|
|
84
|
+
);
|
|
85
|
+
const investorId = `investor-${investor.toLowerCase()}`;
|
|
86
|
+
const investorExists = await anvil.readContract({
|
|
87
|
+
address: registryService,
|
|
88
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
89
|
+
functionName: "isInvestor",
|
|
90
|
+
args: [investorId]
|
|
91
|
+
});
|
|
92
|
+
if (!investorExists) {
|
|
93
|
+
await writeAndWait(anvil, {
|
|
94
|
+
account,
|
|
95
|
+
chain: anvil.chain,
|
|
96
|
+
address: registryService,
|
|
97
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
98
|
+
functionName: "registerInvestor",
|
|
99
|
+
args: [investorId, investorId]
|
|
100
|
+
});
|
|
101
|
+
logger?.debug(`Registered investor "${investorId}"`);
|
|
102
|
+
}
|
|
103
|
+
await writeAndWait(anvil, {
|
|
104
|
+
account,
|
|
105
|
+
chain: anvil.chain,
|
|
106
|
+
address: registryService,
|
|
107
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
108
|
+
functionName: "addWallet",
|
|
109
|
+
args: [investor, investorId]
|
|
110
|
+
});
|
|
111
|
+
logger?.debug(`Added wallet ${investor} for investor "${investorId}"`);
|
|
112
|
+
try {
|
|
113
|
+
await writeAndWait(anvil, {
|
|
114
|
+
account,
|
|
115
|
+
chain: anvil.chain,
|
|
116
|
+
address: registryService,
|
|
117
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
118
|
+
functionName: "setCountry",
|
|
119
|
+
args: [investorId, "US"]
|
|
120
|
+
});
|
|
121
|
+
logger?.debug(`Set country for investor "${investorId}" to "US"`);
|
|
122
|
+
await writeAndWait(anvil, {
|
|
123
|
+
account,
|
|
124
|
+
chain: anvil.chain,
|
|
125
|
+
address: registryService,
|
|
126
|
+
abi: import_iDSRegistryService.iDSRegistryServiceAbi,
|
|
127
|
+
functionName: "setAttribute",
|
|
128
|
+
args: [
|
|
129
|
+
investorId,
|
|
130
|
+
ACCREDITED,
|
|
131
|
+
BigInt(APPROVED),
|
|
132
|
+
import_sdk.MAX_UINT256,
|
|
133
|
+
"fake proof"
|
|
134
|
+
]
|
|
135
|
+
});
|
|
136
|
+
logger?.debug(`Set attributes for investor "${investorId}"`);
|
|
137
|
+
} catch (e) {
|
|
138
|
+
logger?.error(e);
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
logger?.debug(`Investor ${investor} is already a registered wallet`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const MIDAS_MODE_PERMISSIONED = 2;
|
|
145
|
+
const iMidasGatewayExtAbi = (0, import_viem.parseAbi)([
|
|
146
|
+
"function greenlistedRole() external view returns (bytes32)"
|
|
147
|
+
]);
|
|
148
|
+
const iMidasAccessControlAbi = (0, import_viem.parseAbi)([
|
|
149
|
+
"function hasRole(bytes32 role, address account) external view returns (bool)",
|
|
150
|
+
"function getRoleAdmin(bytes32 role) external view returns (bytes32)",
|
|
151
|
+
"function grantRole(bytes32 role, address account) external"
|
|
152
|
+
]);
|
|
153
|
+
async function registerMidasInvestor(props) {
|
|
154
|
+
const { anvil, investor, admin, logger } = props;
|
|
155
|
+
const gateway = await findMidasGateway(props);
|
|
156
|
+
await greenlistMidasGateway({ anvil, investor, admin, gateway, logger });
|
|
157
|
+
}
|
|
158
|
+
async function greenlistMidasGateway(props) {
|
|
159
|
+
const { anvil, investor, admin, gateway, logger } = props;
|
|
160
|
+
const [accessControl, mode, greenlistedRole] = await anvil.multicall({
|
|
161
|
+
allowFailure: false,
|
|
162
|
+
contracts: [
|
|
163
|
+
{
|
|
164
|
+
address: gateway,
|
|
165
|
+
abi: import_withdrawalAbi.midasGatewayAbi,
|
|
166
|
+
functionName: "accessControl"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
address: gateway,
|
|
170
|
+
abi: import_withdrawalAbi.midasGatewayAbi,
|
|
171
|
+
functionName: "mode"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
address: gateway,
|
|
175
|
+
abi: iMidasGatewayExtAbi,
|
|
176
|
+
functionName: "greenlistedRole"
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
});
|
|
180
|
+
if ((0, import_viem.isAddressEqual)(accessControl, import_viem.zeroAddress)) {
|
|
181
|
+
logger?.debug(
|
|
182
|
+
`midas: gateway ${gateway} is permissionless, nothing to greenlist`
|
|
183
|
+
);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const operatorRole = await anvil.readContract({
|
|
187
|
+
address: accessControl,
|
|
188
|
+
abi: iMidasAccessControlAbi,
|
|
189
|
+
functionName: "getRoleAdmin",
|
|
190
|
+
args: [greenlistedRole]
|
|
191
|
+
});
|
|
192
|
+
logger?.debug(
|
|
193
|
+
`midas: gateway ${gateway}, access control ${accessControl}, mode ${mode}, greenlisted role ${greenlistedRole}, operator role ${operatorRole}`
|
|
194
|
+
);
|
|
195
|
+
const grants = [[operatorRole, gateway]];
|
|
196
|
+
if (mode === MIDAS_MODE_PERMISSIONED) {
|
|
197
|
+
grants.push([operatorRole, admin], [greenlistedRole, investor]);
|
|
198
|
+
} else {
|
|
199
|
+
logger?.debug(
|
|
200
|
+
`midas: gateway ${gateway} does not require greenlisted borrowers, only granting the operator role to the gateway`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
const granted = await anvil.multicall({
|
|
204
|
+
allowFailure: false,
|
|
205
|
+
contracts: grants.map(([role, account]) => ({
|
|
206
|
+
address: accessControl,
|
|
207
|
+
abi: iMidasAccessControlAbi,
|
|
208
|
+
functionName: "hasRole",
|
|
209
|
+
args: [role, account]
|
|
210
|
+
}))
|
|
211
|
+
});
|
|
212
|
+
await anvil.impersonateAccount({ address: admin });
|
|
213
|
+
try {
|
|
214
|
+
await anvil.setBalance({ address: admin, value: (0, import_viem.parseEther)("100") });
|
|
215
|
+
for (const [i, [role, account]] of grants.entries()) {
|
|
216
|
+
if (granted[i]) {
|
|
217
|
+
logger?.debug(`midas: ${account} already has role ${role}`);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
await writeAndWait(anvil, {
|
|
221
|
+
account: admin,
|
|
222
|
+
chain: anvil.chain,
|
|
223
|
+
address: accessControl,
|
|
224
|
+
abi: iMidasAccessControlAbi,
|
|
225
|
+
functionName: "grantRole",
|
|
226
|
+
args: [role, account]
|
|
227
|
+
});
|
|
228
|
+
logger?.debug(`midas: granted role ${role} to ${account}`);
|
|
229
|
+
}
|
|
230
|
+
} finally {
|
|
231
|
+
await anvil.stopImpersonatingAccount({ address: admin });
|
|
232
|
+
}
|
|
233
|
+
if (mode === MIDAS_MODE_PERMISSIONED) {
|
|
234
|
+
const isGreenlisted = await anvil.readContract({
|
|
235
|
+
address: accessControl,
|
|
236
|
+
abi: iMidasAccessControlAbi,
|
|
237
|
+
functionName: "hasRole",
|
|
238
|
+
args: [greenlistedRole, investor]
|
|
239
|
+
});
|
|
240
|
+
if (!isGreenlisted) {
|
|
241
|
+
throw new Error(`midas: failed to greenlist investor ${investor}`);
|
|
242
|
+
}
|
|
243
|
+
logger?.debug(`midas: investor ${investor} is greenlisted`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async function findMidasGateway(props) {
|
|
247
|
+
const { anvil, token, marketConfigurators, logger } = props;
|
|
248
|
+
let sdk = props.sdk;
|
|
249
|
+
if (!sdk) {
|
|
250
|
+
sdk = new import_sdk.OnchainSDK(anvil.chain.network, {
|
|
251
|
+
client: anvil,
|
|
252
|
+
timeout: 12e4
|
|
253
|
+
});
|
|
254
|
+
await sdk.attach({ marketConfigurators });
|
|
255
|
+
}
|
|
256
|
+
const candidates = collectMidasGateways(sdk);
|
|
257
|
+
if (candidates.length === 0) {
|
|
258
|
+
throw new Error("no midas gateway adapters found in loaded markets");
|
|
259
|
+
}
|
|
260
|
+
const mTokens = await anvil.multicall({
|
|
261
|
+
allowFailure: false,
|
|
262
|
+
contracts: candidates.map((address) => ({
|
|
263
|
+
address,
|
|
264
|
+
abi: import_withdrawalAbi.midasGatewayAbi,
|
|
265
|
+
functionName: "mToken"
|
|
266
|
+
}))
|
|
267
|
+
});
|
|
268
|
+
const index = mTokens.findIndex((mToken) => (0, import_viem.isAddressEqual)(mToken, token));
|
|
269
|
+
if (index === -1) {
|
|
270
|
+
throw new Error(`no midas gateway found for token ${token}`);
|
|
271
|
+
}
|
|
272
|
+
logger?.debug(`midas: gateway for ${token} is ${candidates[index]}`);
|
|
273
|
+
return candidates[index];
|
|
274
|
+
}
|
|
275
|
+
function collectMidasGateways(sdk) {
|
|
276
|
+
const gateways = new import_sdk.AddressSet();
|
|
277
|
+
for (const cm of sdk.marketRegister.creditManagers) {
|
|
278
|
+
for (const adapter of cm.creditManager.adapters.values()) {
|
|
279
|
+
if (adapter.contractType === "ADAPTER::MIDAS_GATEWAY") {
|
|
280
|
+
gateways.add(adapter.targetContract);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return gateways.asArray();
|
|
285
|
+
}
|
|
286
|
+
async function registerRWAInvestor(props) {
|
|
287
|
+
const { anvil, sdk, investor, adminPrivateKey, midasAdmin, logger } = props;
|
|
288
|
+
const securitizeTokens = [];
|
|
289
|
+
const midasGateways = [];
|
|
290
|
+
const failed = [];
|
|
291
|
+
const dsTokens = new import_sdk.AddressSet(
|
|
292
|
+
sdk.rwa.factories.flatMap((factory) => factory.getTokens())
|
|
293
|
+
);
|
|
294
|
+
if (adminPrivateKey) {
|
|
295
|
+
for (const token of dsTokens) {
|
|
296
|
+
try {
|
|
297
|
+
await registerSecuritizeInvestor({
|
|
298
|
+
anvil,
|
|
299
|
+
investor,
|
|
300
|
+
adminPrivateKey,
|
|
301
|
+
token,
|
|
302
|
+
logger
|
|
303
|
+
});
|
|
304
|
+
securitizeTokens.push(token);
|
|
305
|
+
} catch (e) {
|
|
306
|
+
logger?.error(`securitize: failed to register ${investor} in ${token}`);
|
|
307
|
+
logger?.error(e);
|
|
308
|
+
failed.push({ target: token, error: e });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} else if (dsTokens.size > 0) {
|
|
312
|
+
logger?.warn(
|
|
313
|
+
`securitize: no admin private key, skipping ${dsTokens.size} DSToken(s)`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const gateways = collectMidasGateways(sdk);
|
|
317
|
+
if (midasAdmin) {
|
|
318
|
+
for (const gateway of gateways) {
|
|
319
|
+
try {
|
|
320
|
+
await greenlistMidasGateway({
|
|
321
|
+
anvil,
|
|
322
|
+
investor,
|
|
323
|
+
admin: midasAdmin,
|
|
324
|
+
gateway,
|
|
325
|
+
logger
|
|
326
|
+
});
|
|
327
|
+
midasGateways.push(gateway);
|
|
328
|
+
} catch (e) {
|
|
329
|
+
logger?.error(`midas: failed to greenlist ${investor} in ${gateway}`);
|
|
330
|
+
logger?.error(e);
|
|
331
|
+
failed.push({ target: gateway, error: e });
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
} else if (gateways.length > 0) {
|
|
335
|
+
logger?.warn(
|
|
336
|
+
`midas: no access control admin, skipping ${gateways.length} gateway(s)`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
logger?.debug(
|
|
340
|
+
`${investor} passed KYC on ${securitizeTokens.length} DSToken(s) and ${midasGateways.length} midas gateway(s), ${failed.length} failure(s)`
|
|
341
|
+
);
|
|
342
|
+
return { securitizeTokens, midasGateways, failed };
|
|
343
|
+
}
|
|
344
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
345
|
+
0 && (module.exports = {
|
|
346
|
+
greenlistMidasGateway,
|
|
347
|
+
registerMidasInvestor,
|
|
348
|
+
registerRWAInvestor,
|
|
349
|
+
registerSecuritizeInvestor,
|
|
350
|
+
writeAndWait
|
|
351
|
+
});
|
|
@@ -2,126 +2,13 @@ import {
|
|
|
2
2
|
erc20Abi
|
|
3
3
|
} from "viem";
|
|
4
4
|
import { privateKeyToAccount } from "viem/accounts";
|
|
5
|
-
import { iDSRegistryServiceAbi } from "../abi/rwa/iDSRegistryService.js";
|
|
6
5
|
import { iDSTokenAbi } from "../abi/rwa/iDSToken.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
OnchainSDK
|
|
10
|
-
} from "../sdk/index.js";
|
|
11
|
-
async function writeAndWait(anvil, params) {
|
|
12
|
-
const hash = await anvil.writeContract(params);
|
|
13
|
-
await anvil.mine({ blocks: 1 });
|
|
14
|
-
await anvil.waitForTransactionReceipt({
|
|
15
|
-
hash,
|
|
16
|
-
pollingInterval: 100
|
|
17
|
-
});
|
|
18
|
-
return hash;
|
|
19
|
-
}
|
|
20
|
-
async function registerInvestor(props) {
|
|
21
|
-
const { claimer, anvil, token, adminPrivateKey, logger } = props;
|
|
22
|
-
const account = privateKeyToAccount(adminPrivateKey);
|
|
23
|
-
const registryServiceId = await anvil.readContract({
|
|
24
|
-
address: token,
|
|
25
|
-
abi: iDSTokenAbi,
|
|
26
|
-
functionName: "REGISTRY_SERVICE"
|
|
27
|
-
});
|
|
28
|
-
const registryService = await anvil.readContract({
|
|
29
|
-
address: token,
|
|
30
|
-
abi: iDSTokenAbi,
|
|
31
|
-
functionName: "getDSService",
|
|
32
|
-
args: [registryServiceId]
|
|
33
|
-
});
|
|
34
|
-
logger?.debug(`Registry service: ${registryService} (${registryServiceId})`);
|
|
35
|
-
const [isRegistered, ACCREDITED, APPROVED] = await anvil.multicall({
|
|
36
|
-
contracts: [
|
|
37
|
-
{
|
|
38
|
-
address: registryService,
|
|
39
|
-
abi: iDSRegistryServiceAbi,
|
|
40
|
-
functionName: "isWallet",
|
|
41
|
-
args: [claimer]
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
address: registryService,
|
|
45
|
-
abi: iDSRegistryServiceAbi,
|
|
46
|
-
functionName: "ACCREDITED",
|
|
47
|
-
args: []
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
address: registryService,
|
|
51
|
-
abi: iDSRegistryServiceAbi,
|
|
52
|
-
functionName: "APPROVED",
|
|
53
|
-
args: []
|
|
54
|
-
}
|
|
55
|
-
],
|
|
56
|
-
allowFailure: false
|
|
57
|
-
});
|
|
58
|
-
if (!isRegistered) {
|
|
59
|
-
logger?.debug(
|
|
60
|
-
`Claimer ${claimer} is not a registered wallet, registering...`
|
|
61
|
-
);
|
|
62
|
-
const investorId = `investor-${claimer.toLowerCase()}`;
|
|
63
|
-
const investorExists = await anvil.readContract({
|
|
64
|
-
address: registryService,
|
|
65
|
-
abi: iDSRegistryServiceAbi,
|
|
66
|
-
functionName: "isInvestor",
|
|
67
|
-
args: [investorId]
|
|
68
|
-
});
|
|
69
|
-
if (!investorExists) {
|
|
70
|
-
await writeAndWait(anvil, {
|
|
71
|
-
account,
|
|
72
|
-
chain: anvil.chain,
|
|
73
|
-
address: registryService,
|
|
74
|
-
abi: iDSRegistryServiceAbi,
|
|
75
|
-
functionName: "registerInvestor",
|
|
76
|
-
args: [investorId, investorId]
|
|
77
|
-
});
|
|
78
|
-
logger?.debug(`Registered investor "${investorId}"`);
|
|
79
|
-
}
|
|
80
|
-
await writeAndWait(anvil, {
|
|
81
|
-
account,
|
|
82
|
-
chain: anvil.chain,
|
|
83
|
-
address: registryService,
|
|
84
|
-
abi: iDSRegistryServiceAbi,
|
|
85
|
-
functionName: "addWallet",
|
|
86
|
-
args: [claimer, investorId]
|
|
87
|
-
});
|
|
88
|
-
logger?.debug(`Added wallet ${claimer} for investor "${investorId}"`);
|
|
89
|
-
try {
|
|
90
|
-
await writeAndWait(anvil, {
|
|
91
|
-
account,
|
|
92
|
-
chain: anvil.chain,
|
|
93
|
-
address: registryService,
|
|
94
|
-
abi: iDSRegistryServiceAbi,
|
|
95
|
-
functionName: "setCountry",
|
|
96
|
-
args: [investorId, "US"]
|
|
97
|
-
});
|
|
98
|
-
logger?.debug(`Set country for investor "${investorId}" to "US"`);
|
|
99
|
-
await writeAndWait(anvil, {
|
|
100
|
-
account,
|
|
101
|
-
chain: anvil.chain,
|
|
102
|
-
address: registryService,
|
|
103
|
-
abi: iDSRegistryServiceAbi,
|
|
104
|
-
functionName: "setAttribute",
|
|
105
|
-
args: [
|
|
106
|
-
investorId,
|
|
107
|
-
ACCREDITED,
|
|
108
|
-
BigInt(APPROVED),
|
|
109
|
-
MAX_UINT256,
|
|
110
|
-
"fake proof"
|
|
111
|
-
]
|
|
112
|
-
});
|
|
113
|
-
logger?.debug(`Set attributes for investor "${investorId}"`);
|
|
114
|
-
} catch (e) {
|
|
115
|
-
logger?.error(e);
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
logger?.debug(`Claimer ${claimer} is already a registered wallet`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
6
|
+
import { OnchainSDK } from "../sdk/index.js";
|
|
7
|
+
import { registerSecuritizeInvestor, writeAndWait } from "./kycUtils.js";
|
|
121
8
|
async function claimDSToken(props) {
|
|
122
9
|
const {
|
|
123
10
|
anvil,
|
|
124
|
-
|
|
11
|
+
investor,
|
|
125
12
|
adminPrivateKey,
|
|
126
13
|
token,
|
|
127
14
|
marketConfigurators,
|
|
@@ -153,25 +40,25 @@ async function claimDSToken(props) {
|
|
|
153
40
|
throw new Error(`No market found for token ${token}`);
|
|
154
41
|
}
|
|
155
42
|
logger?.debug(`${usdAmountProp} USD === ${amount} ${symbol}`);
|
|
156
|
-
await
|
|
157
|
-
logger?.debug(`Issuing ${amount} tokens to ${
|
|
43
|
+
await registerSecuritizeInvestor({ ...props, logger });
|
|
44
|
+
logger?.debug(`Issuing ${amount} tokens to ${investor}...`);
|
|
158
45
|
const mintHash = await writeAndWait(anvil, {
|
|
159
46
|
account,
|
|
160
47
|
chain: anvil.chain,
|
|
161
48
|
address: token,
|
|
162
49
|
abi: iDSTokenAbi,
|
|
163
50
|
functionName: "issueTokens",
|
|
164
|
-
args: [
|
|
51
|
+
args: [investor, amount]
|
|
165
52
|
});
|
|
166
53
|
logger?.debug(`Done! tx: ${mintHash}`);
|
|
167
54
|
const balance = await anvil.readContract({
|
|
168
55
|
address: token,
|
|
169
56
|
abi: erc20Abi,
|
|
170
57
|
functionName: "balanceOf",
|
|
171
|
-
args: [
|
|
58
|
+
args: [investor]
|
|
172
59
|
});
|
|
173
60
|
logger?.debug(
|
|
174
|
-
`Balance of ${
|
|
61
|
+
`Balance of ${investor}: ${sdk.tokensMeta.formatBN(token, balance)}`
|
|
175
62
|
);
|
|
176
63
|
}
|
|
177
64
|
async function claimDSTokens(props) {
|
|
@@ -182,6 +69,5 @@ async function claimDSTokens(props) {
|
|
|
182
69
|
}
|
|
183
70
|
export {
|
|
184
71
|
claimDSToken,
|
|
185
|
-
claimDSTokens
|
|
186
|
-
registerInvestor
|
|
72
|
+
claimDSTokens
|
|
187
73
|
};
|
package/dist/esm/dev/index.js
CHANGED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isAddressEqual,
|
|
3
|
+
parseAbi,
|
|
4
|
+
parseEther,
|
|
5
|
+
zeroAddress
|
|
6
|
+
} from "viem";
|
|
7
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
8
|
+
import { iDSRegistryServiceAbi } from "../abi/rwa/iDSRegistryService.js";
|
|
9
|
+
import { iDSTokenAbi } from "../abi/rwa/iDSToken.js";
|
|
10
|
+
import {
|
|
11
|
+
AddressSet,
|
|
12
|
+
MAX_UINT256,
|
|
13
|
+
OnchainSDK
|
|
14
|
+
} from "../sdk/index.js";
|
|
15
|
+
import { midasGatewayAbi } from "./withdrawalAbi.js";
|
|
16
|
+
async function writeAndWait(anvil, params) {
|
|
17
|
+
const hash = await anvil.writeContract(params);
|
|
18
|
+
await anvil.mine({ blocks: 1 });
|
|
19
|
+
await anvil.waitForTransactionReceipt({
|
|
20
|
+
hash,
|
|
21
|
+
pollingInterval: 100
|
|
22
|
+
});
|
|
23
|
+
return hash;
|
|
24
|
+
}
|
|
25
|
+
async function registerSecuritizeInvestor(props) {
|
|
26
|
+
const { investor, anvil, token, adminPrivateKey, logger } = props;
|
|
27
|
+
const account = privateKeyToAccount(adminPrivateKey);
|
|
28
|
+
const registryServiceId = await anvil.readContract({
|
|
29
|
+
address: token,
|
|
30
|
+
abi: iDSTokenAbi,
|
|
31
|
+
functionName: "REGISTRY_SERVICE"
|
|
32
|
+
});
|
|
33
|
+
const registryService = await anvil.readContract({
|
|
34
|
+
address: token,
|
|
35
|
+
abi: iDSTokenAbi,
|
|
36
|
+
functionName: "getDSService",
|
|
37
|
+
args: [registryServiceId]
|
|
38
|
+
});
|
|
39
|
+
logger?.debug(`Registry service: ${registryService} (${registryServiceId})`);
|
|
40
|
+
const [isRegistered, ACCREDITED, APPROVED] = await anvil.multicall({
|
|
41
|
+
contracts: [
|
|
42
|
+
{
|
|
43
|
+
address: registryService,
|
|
44
|
+
abi: iDSRegistryServiceAbi,
|
|
45
|
+
functionName: "isWallet",
|
|
46
|
+
args: [investor]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
address: registryService,
|
|
50
|
+
abi: iDSRegistryServiceAbi,
|
|
51
|
+
functionName: "ACCREDITED",
|
|
52
|
+
args: []
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
address: registryService,
|
|
56
|
+
abi: iDSRegistryServiceAbi,
|
|
57
|
+
functionName: "APPROVED",
|
|
58
|
+
args: []
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
allowFailure: false
|
|
62
|
+
});
|
|
63
|
+
if (!isRegistered) {
|
|
64
|
+
logger?.debug(
|
|
65
|
+
`Investor ${investor} is not a registered wallet, registering...`
|
|
66
|
+
);
|
|
67
|
+
const investorId = `investor-${investor.toLowerCase()}`;
|
|
68
|
+
const investorExists = await anvil.readContract({
|
|
69
|
+
address: registryService,
|
|
70
|
+
abi: iDSRegistryServiceAbi,
|
|
71
|
+
functionName: "isInvestor",
|
|
72
|
+
args: [investorId]
|
|
73
|
+
});
|
|
74
|
+
if (!investorExists) {
|
|
75
|
+
await writeAndWait(anvil, {
|
|
76
|
+
account,
|
|
77
|
+
chain: anvil.chain,
|
|
78
|
+
address: registryService,
|
|
79
|
+
abi: iDSRegistryServiceAbi,
|
|
80
|
+
functionName: "registerInvestor",
|
|
81
|
+
args: [investorId, investorId]
|
|
82
|
+
});
|
|
83
|
+
logger?.debug(`Registered investor "${investorId}"`);
|
|
84
|
+
}
|
|
85
|
+
await writeAndWait(anvil, {
|
|
86
|
+
account,
|
|
87
|
+
chain: anvil.chain,
|
|
88
|
+
address: registryService,
|
|
89
|
+
abi: iDSRegistryServiceAbi,
|
|
90
|
+
functionName: "addWallet",
|
|
91
|
+
args: [investor, investorId]
|
|
92
|
+
});
|
|
93
|
+
logger?.debug(`Added wallet ${investor} for investor "${investorId}"`);
|
|
94
|
+
try {
|
|
95
|
+
await writeAndWait(anvil, {
|
|
96
|
+
account,
|
|
97
|
+
chain: anvil.chain,
|
|
98
|
+
address: registryService,
|
|
99
|
+
abi: iDSRegistryServiceAbi,
|
|
100
|
+
functionName: "setCountry",
|
|
101
|
+
args: [investorId, "US"]
|
|
102
|
+
});
|
|
103
|
+
logger?.debug(`Set country for investor "${investorId}" to "US"`);
|
|
104
|
+
await writeAndWait(anvil, {
|
|
105
|
+
account,
|
|
106
|
+
chain: anvil.chain,
|
|
107
|
+
address: registryService,
|
|
108
|
+
abi: iDSRegistryServiceAbi,
|
|
109
|
+
functionName: "setAttribute",
|
|
110
|
+
args: [
|
|
111
|
+
investorId,
|
|
112
|
+
ACCREDITED,
|
|
113
|
+
BigInt(APPROVED),
|
|
114
|
+
MAX_UINT256,
|
|
115
|
+
"fake proof"
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
logger?.debug(`Set attributes for investor "${investorId}"`);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
logger?.error(e);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
logger?.debug(`Investor ${investor} is already a registered wallet`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const MIDAS_MODE_PERMISSIONED = 2;
|
|
127
|
+
const iMidasGatewayExtAbi = parseAbi([
|
|
128
|
+
"function greenlistedRole() external view returns (bytes32)"
|
|
129
|
+
]);
|
|
130
|
+
const iMidasAccessControlAbi = parseAbi([
|
|
131
|
+
"function hasRole(bytes32 role, address account) external view returns (bool)",
|
|
132
|
+
"function getRoleAdmin(bytes32 role) external view returns (bytes32)",
|
|
133
|
+
"function grantRole(bytes32 role, address account) external"
|
|
134
|
+
]);
|
|
135
|
+
async function registerMidasInvestor(props) {
|
|
136
|
+
const { anvil, investor, admin, logger } = props;
|
|
137
|
+
const gateway = await findMidasGateway(props);
|
|
138
|
+
await greenlistMidasGateway({ anvil, investor, admin, gateway, logger });
|
|
139
|
+
}
|
|
140
|
+
async function greenlistMidasGateway(props) {
|
|
141
|
+
const { anvil, investor, admin, gateway, logger } = props;
|
|
142
|
+
const [accessControl, mode, greenlistedRole] = await anvil.multicall({
|
|
143
|
+
allowFailure: false,
|
|
144
|
+
contracts: [
|
|
145
|
+
{
|
|
146
|
+
address: gateway,
|
|
147
|
+
abi: midasGatewayAbi,
|
|
148
|
+
functionName: "accessControl"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
address: gateway,
|
|
152
|
+
abi: midasGatewayAbi,
|
|
153
|
+
functionName: "mode"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
address: gateway,
|
|
157
|
+
abi: iMidasGatewayExtAbi,
|
|
158
|
+
functionName: "greenlistedRole"
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
if (isAddressEqual(accessControl, zeroAddress)) {
|
|
163
|
+
logger?.debug(
|
|
164
|
+
`midas: gateway ${gateway} is permissionless, nothing to greenlist`
|
|
165
|
+
);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const operatorRole = await anvil.readContract({
|
|
169
|
+
address: accessControl,
|
|
170
|
+
abi: iMidasAccessControlAbi,
|
|
171
|
+
functionName: "getRoleAdmin",
|
|
172
|
+
args: [greenlistedRole]
|
|
173
|
+
});
|
|
174
|
+
logger?.debug(
|
|
175
|
+
`midas: gateway ${gateway}, access control ${accessControl}, mode ${mode}, greenlisted role ${greenlistedRole}, operator role ${operatorRole}`
|
|
176
|
+
);
|
|
177
|
+
const grants = [[operatorRole, gateway]];
|
|
178
|
+
if (mode === MIDAS_MODE_PERMISSIONED) {
|
|
179
|
+
grants.push([operatorRole, admin], [greenlistedRole, investor]);
|
|
180
|
+
} else {
|
|
181
|
+
logger?.debug(
|
|
182
|
+
`midas: gateway ${gateway} does not require greenlisted borrowers, only granting the operator role to the gateway`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const granted = await anvil.multicall({
|
|
186
|
+
allowFailure: false,
|
|
187
|
+
contracts: grants.map(([role, account]) => ({
|
|
188
|
+
address: accessControl,
|
|
189
|
+
abi: iMidasAccessControlAbi,
|
|
190
|
+
functionName: "hasRole",
|
|
191
|
+
args: [role, account]
|
|
192
|
+
}))
|
|
193
|
+
});
|
|
194
|
+
await anvil.impersonateAccount({ address: admin });
|
|
195
|
+
try {
|
|
196
|
+
await anvil.setBalance({ address: admin, value: parseEther("100") });
|
|
197
|
+
for (const [i, [role, account]] of grants.entries()) {
|
|
198
|
+
if (granted[i]) {
|
|
199
|
+
logger?.debug(`midas: ${account} already has role ${role}`);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
await writeAndWait(anvil, {
|
|
203
|
+
account: admin,
|
|
204
|
+
chain: anvil.chain,
|
|
205
|
+
address: accessControl,
|
|
206
|
+
abi: iMidasAccessControlAbi,
|
|
207
|
+
functionName: "grantRole",
|
|
208
|
+
args: [role, account]
|
|
209
|
+
});
|
|
210
|
+
logger?.debug(`midas: granted role ${role} to ${account}`);
|
|
211
|
+
}
|
|
212
|
+
} finally {
|
|
213
|
+
await anvil.stopImpersonatingAccount({ address: admin });
|
|
214
|
+
}
|
|
215
|
+
if (mode === MIDAS_MODE_PERMISSIONED) {
|
|
216
|
+
const isGreenlisted = await anvil.readContract({
|
|
217
|
+
address: accessControl,
|
|
218
|
+
abi: iMidasAccessControlAbi,
|
|
219
|
+
functionName: "hasRole",
|
|
220
|
+
args: [greenlistedRole, investor]
|
|
221
|
+
});
|
|
222
|
+
if (!isGreenlisted) {
|
|
223
|
+
throw new Error(`midas: failed to greenlist investor ${investor}`);
|
|
224
|
+
}
|
|
225
|
+
logger?.debug(`midas: investor ${investor} is greenlisted`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function findMidasGateway(props) {
|
|
229
|
+
const { anvil, token, marketConfigurators, logger } = props;
|
|
230
|
+
let sdk = props.sdk;
|
|
231
|
+
if (!sdk) {
|
|
232
|
+
sdk = new OnchainSDK(anvil.chain.network, {
|
|
233
|
+
client: anvil,
|
|
234
|
+
timeout: 12e4
|
|
235
|
+
});
|
|
236
|
+
await sdk.attach({ marketConfigurators });
|
|
237
|
+
}
|
|
238
|
+
const candidates = collectMidasGateways(sdk);
|
|
239
|
+
if (candidates.length === 0) {
|
|
240
|
+
throw new Error("no midas gateway adapters found in loaded markets");
|
|
241
|
+
}
|
|
242
|
+
const mTokens = await anvil.multicall({
|
|
243
|
+
allowFailure: false,
|
|
244
|
+
contracts: candidates.map((address) => ({
|
|
245
|
+
address,
|
|
246
|
+
abi: midasGatewayAbi,
|
|
247
|
+
functionName: "mToken"
|
|
248
|
+
}))
|
|
249
|
+
});
|
|
250
|
+
const index = mTokens.findIndex((mToken) => isAddressEqual(mToken, token));
|
|
251
|
+
if (index === -1) {
|
|
252
|
+
throw new Error(`no midas gateway found for token ${token}`);
|
|
253
|
+
}
|
|
254
|
+
logger?.debug(`midas: gateway for ${token} is ${candidates[index]}`);
|
|
255
|
+
return candidates[index];
|
|
256
|
+
}
|
|
257
|
+
function collectMidasGateways(sdk) {
|
|
258
|
+
const gateways = new AddressSet();
|
|
259
|
+
for (const cm of sdk.marketRegister.creditManagers) {
|
|
260
|
+
for (const adapter of cm.creditManager.adapters.values()) {
|
|
261
|
+
if (adapter.contractType === "ADAPTER::MIDAS_GATEWAY") {
|
|
262
|
+
gateways.add(adapter.targetContract);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return gateways.asArray();
|
|
267
|
+
}
|
|
268
|
+
async function registerRWAInvestor(props) {
|
|
269
|
+
const { anvil, sdk, investor, adminPrivateKey, midasAdmin, logger } = props;
|
|
270
|
+
const securitizeTokens = [];
|
|
271
|
+
const midasGateways = [];
|
|
272
|
+
const failed = [];
|
|
273
|
+
const dsTokens = new AddressSet(
|
|
274
|
+
sdk.rwa.factories.flatMap((factory) => factory.getTokens())
|
|
275
|
+
);
|
|
276
|
+
if (adminPrivateKey) {
|
|
277
|
+
for (const token of dsTokens) {
|
|
278
|
+
try {
|
|
279
|
+
await registerSecuritizeInvestor({
|
|
280
|
+
anvil,
|
|
281
|
+
investor,
|
|
282
|
+
adminPrivateKey,
|
|
283
|
+
token,
|
|
284
|
+
logger
|
|
285
|
+
});
|
|
286
|
+
securitizeTokens.push(token);
|
|
287
|
+
} catch (e) {
|
|
288
|
+
logger?.error(`securitize: failed to register ${investor} in ${token}`);
|
|
289
|
+
logger?.error(e);
|
|
290
|
+
failed.push({ target: token, error: e });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
} else if (dsTokens.size > 0) {
|
|
294
|
+
logger?.warn(
|
|
295
|
+
`securitize: no admin private key, skipping ${dsTokens.size} DSToken(s)`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const gateways = collectMidasGateways(sdk);
|
|
299
|
+
if (midasAdmin) {
|
|
300
|
+
for (const gateway of gateways) {
|
|
301
|
+
try {
|
|
302
|
+
await greenlistMidasGateway({
|
|
303
|
+
anvil,
|
|
304
|
+
investor,
|
|
305
|
+
admin: midasAdmin,
|
|
306
|
+
gateway,
|
|
307
|
+
logger
|
|
308
|
+
});
|
|
309
|
+
midasGateways.push(gateway);
|
|
310
|
+
} catch (e) {
|
|
311
|
+
logger?.error(`midas: failed to greenlist ${investor} in ${gateway}`);
|
|
312
|
+
logger?.error(e);
|
|
313
|
+
failed.push({ target: gateway, error: e });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} else if (gateways.length > 0) {
|
|
317
|
+
logger?.warn(
|
|
318
|
+
`midas: no access control admin, skipping ${gateways.length} gateway(s)`
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
logger?.debug(
|
|
322
|
+
`${investor} passed KYC on ${securitizeTokens.length} DSToken(s) and ${midasGateways.length} midas gateway(s), ${failed.length} failure(s)`
|
|
323
|
+
);
|
|
324
|
+
return { securitizeTokens, midasGateways, failed };
|
|
325
|
+
}
|
|
326
|
+
export {
|
|
327
|
+
greenlistMidasGateway,
|
|
328
|
+
registerMidasInvestor,
|
|
329
|
+
registerRWAInvestor,
|
|
330
|
+
registerSecuritizeInvestor,
|
|
331
|
+
writeAndWait
|
|
332
|
+
};
|
|
@@ -3,7 +3,7 @@ import { type ILogger } from "../sdk/index.js";
|
|
|
3
3
|
import type { AnvilClient } from "./createAnvilClient.js";
|
|
4
4
|
interface ClaimDSTokenProps {
|
|
5
5
|
anvil: AnvilClient;
|
|
6
|
-
|
|
6
|
+
investor: Address;
|
|
7
7
|
adminPrivateKey: Hex;
|
|
8
8
|
/**
|
|
9
9
|
* DSToken addresses
|
|
@@ -20,14 +20,13 @@ interface ClaimDSTokenProps {
|
|
|
20
20
|
type ClaimDSTokensProps = Omit<ClaimDSTokenProps, "token"> & {
|
|
21
21
|
tokens: Address[];
|
|
22
22
|
};
|
|
23
|
-
export declare function registerInvestor(props: ClaimDSTokenProps): Promise<void>;
|
|
24
23
|
export declare function claimDSToken(props: ClaimDSTokenProps): Promise<void>;
|
|
25
24
|
/**
|
|
26
25
|
* Helper function to claim DSToken from the faucet.
|
|
27
26
|
* Works both for MockDStoken and real DSToken connected by securitize-deploy script
|
|
28
27
|
* @param forkStatus
|
|
29
28
|
* @param publicClient
|
|
30
|
-
* @param
|
|
29
|
+
* @param investor
|
|
31
30
|
* @returns
|
|
32
31
|
*/
|
|
33
32
|
export declare function claimDSTokens(props: ClaimDSTokensProps): Promise<void>;
|
|
@@ -10,6 +10,7 @@ export * from "./EthCallSpy.js";
|
|
|
10
10
|
export * from "./isOutOfSyncError.js";
|
|
11
11
|
export * from "./isRateLimitError.js";
|
|
12
12
|
export * from "./isTransientError.js";
|
|
13
|
+
export * from "./kycUtils.js";
|
|
13
14
|
export { isRangeError, type LogSplitterTransportOptions, logSplitterTransport, } from "./logSplitterTransport.js";
|
|
14
15
|
export * from "./ltUtils.js";
|
|
15
16
|
export * from "./migrateFaucet.js";
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { type Address, type Hex } from "viem";
|
|
2
|
+
import { type ILogger, OnchainSDK } from "../sdk/index.js";
|
|
3
|
+
import type { AnvilClient } from "./createAnvilClient.js";
|
|
4
|
+
/**
|
|
5
|
+
* Writes to a contract, mines a block and waits for the receipt
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeAndWait(anvil: AnvilClient, params: Parameters<AnvilClient["writeContract"]>[0]): Promise<Hex>;
|
|
8
|
+
export interface RegisterSecuritizeInvestorProps {
|
|
9
|
+
anvil: AnvilClient;
|
|
10
|
+
/**
|
|
11
|
+
* Wallet to register in the Securitize DS registry
|
|
12
|
+
*/
|
|
13
|
+
investor: Address;
|
|
14
|
+
adminPrivateKey: Hex;
|
|
15
|
+
/**
|
|
16
|
+
* DSToken address
|
|
17
|
+
*/
|
|
18
|
+
token: Address;
|
|
19
|
+
logger?: ILogger;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Registers a wallet as a Securitize investor (fake KYC) in the DS registry
|
|
23
|
+
* service of a DSToken.
|
|
24
|
+
* Works both for MockDSToken and real DSToken connected by securitize-deploy script
|
|
25
|
+
*/
|
|
26
|
+
export declare function registerSecuritizeInvestor(props: RegisterSecuritizeInvestorProps): Promise<void>;
|
|
27
|
+
export interface RegisterMidasInvestorProps {
|
|
28
|
+
anvil: AnvilClient;
|
|
29
|
+
/**
|
|
30
|
+
* Investor EOA to greenlist
|
|
31
|
+
*/
|
|
32
|
+
investor: Address;
|
|
33
|
+
/**
|
|
34
|
+
* Midas access control admin, impersonated on the fork
|
|
35
|
+
* (MIDAS_ACL_ADMIN in periphery-v3/router-v3 foundry tests)
|
|
36
|
+
*/
|
|
37
|
+
admin: Address;
|
|
38
|
+
/**
|
|
39
|
+
* mToken address, the gateway is resolved from it
|
|
40
|
+
*/
|
|
41
|
+
token: Address;
|
|
42
|
+
/**
|
|
43
|
+
* Attached SDK, created from `anvil` when omitted
|
|
44
|
+
*/
|
|
45
|
+
sdk?: OnchainSDK;
|
|
46
|
+
marketConfigurators?: Address[];
|
|
47
|
+
logger?: ILogger;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Greenlists an investor in Midas access control (fake KYC) on an anvil fork.
|
|
51
|
+
*
|
|
52
|
+
* Replicates the `_grantGreenlistAdmin` / `_grantGreenlist` logic from the
|
|
53
|
+
* foundry tests (periphery-v3's WithdrawalCompressorMidasRWA.t.sol and
|
|
54
|
+
* router-v3's RouterLiveTestMidas.sol) by impersonating the Midas access
|
|
55
|
+
* control admin instead of pranking it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function registerMidasInvestor(props: RegisterMidasInvestorProps): Promise<void>;
|
|
58
|
+
export interface GreenlistMidasGatewayProps {
|
|
59
|
+
anvil: AnvilClient;
|
|
60
|
+
/**
|
|
61
|
+
* Investor EOA to greenlist
|
|
62
|
+
*/
|
|
63
|
+
investor: Address;
|
|
64
|
+
/**
|
|
65
|
+
* Midas access control admin, impersonated on the fork
|
|
66
|
+
* (MIDAS_ACL_ADMIN in periphery-v3/router-v3 foundry tests)
|
|
67
|
+
*/
|
|
68
|
+
admin: Address;
|
|
69
|
+
/**
|
|
70
|
+
* Midas gateway address
|
|
71
|
+
*/
|
|
72
|
+
gateway: Address;
|
|
73
|
+
logger?: ILogger;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Greenlists an investor in the access control of a single Midas gateway
|
|
77
|
+
*/
|
|
78
|
+
export declare function greenlistMidasGateway(props: GreenlistMidasGatewayProps): Promise<void>;
|
|
79
|
+
export interface RegisterRWAInvestorProps {
|
|
80
|
+
anvil: AnvilClient;
|
|
81
|
+
/**
|
|
82
|
+
* Attached SDK, markets and RWA factories are read from it
|
|
83
|
+
*/
|
|
84
|
+
sdk: OnchainSDK;
|
|
85
|
+
/**
|
|
86
|
+
* Wallet to pass the KYC of every RWA token
|
|
87
|
+
*/
|
|
88
|
+
investor: Address;
|
|
89
|
+
/**
|
|
90
|
+
* Securitize registry admin, DSTokens are skipped when omitted
|
|
91
|
+
*/
|
|
92
|
+
adminPrivateKey?: Hex;
|
|
93
|
+
/**
|
|
94
|
+
* Midas access control admin, Midas gateways are skipped when omitted
|
|
95
|
+
*/
|
|
96
|
+
midasAdmin?: Address;
|
|
97
|
+
logger?: ILogger;
|
|
98
|
+
}
|
|
99
|
+
export interface RWAKycFailure {
|
|
100
|
+
/**
|
|
101
|
+
* DSToken or Midas gateway that failed
|
|
102
|
+
*/
|
|
103
|
+
target: Address;
|
|
104
|
+
error: unknown;
|
|
105
|
+
}
|
|
106
|
+
export interface RegisterRWAInvestorResult {
|
|
107
|
+
/**
|
|
108
|
+
* DSTokens the investor was registered in
|
|
109
|
+
*/
|
|
110
|
+
securitizeTokens: Address[];
|
|
111
|
+
/**
|
|
112
|
+
* Midas gateways the investor was greenlisted in
|
|
113
|
+
*/
|
|
114
|
+
midasGateways: Address[];
|
|
115
|
+
failed: RWAKycFailure[];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Registers a wallet as an investor (fake KYC) in every Securitize DSToken and
|
|
119
|
+
* every Midas gateway of the markets loaded by `sdk`.
|
|
120
|
+
*
|
|
121
|
+
* Failures of a single token or gateway are collected and reported in the
|
|
122
|
+
* result instead of aborting the whole run.
|
|
123
|
+
*/
|
|
124
|
+
export declare function registerRWAInvestor(props: RegisterRWAInvestorProps): Promise<RegisterRWAInvestorResult>;
|