-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.ts
122 lines (106 loc) · 2.82 KB
/
server.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import 'dotenv/config';
import rpc from 'json-rpc2';
import { JsonRpcProvider } from '@ethersproject/providers';
import { BigNumber, Contract, utils, Wallet } from 'ethers';
import EssentialForwarder from './abis/EssentialForwarder.json';
const OWNER_ABI = [
{
inputs: [
{
internalType: 'uint256',
name: 'tokenId',
type: 'uint256',
},
],
name: 'ownerOf',
outputs: [
{
internalType: 'address',
name: '',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
},
];
const server = rpc.Server.$create({
headers: {
'Access-Control-Allow-Origin': '*',
},
});
function decodeCalldata(calldata: string): Record<string, any> {
const abi = new utils.AbiCoder();
const [from, nonce, nftContract, tokenId, tokenNonce] = abi.decode(
['address', 'uint256', 'address', 'uint256', 'uint256'],
calldata,
);
return { from, nonce, nftContract, tokenId, tokenNonce };
}
async function fetchCurrentOwner(
nftContract: string,
tokenId: BigNumber,
): Promise<string> {
const mainnetProvider = new JsonRpcProvider(process.env.MAINNET_RPC_URL, 1);
const Erc721 = new Contract(nftContract, OWNER_ABI, mainnetProvider);
return Erc721.ownerOf(tokenId);
}
async function generateProof({
owner,
nonce,
nftContract,
tokenId,
to,
tokenNonce
// abi,
}): Promise<string> {
// This EOA won't have any assets, and can be easily changed on the Forwarding
// contract, so the risk profile is pretty low. We use this on the L2 to fetch
// the message to sign.
const altnetProvider = new JsonRpcProvider(process.env.ALTNET_RPC_URL);
const ownershipSigner = new Wallet(
process.env.OWNERSHIP_SIGNER_PRIVATE_KEY,
altnetProvider,
);
const forwarder = new Contract(to, EssentialForwarder.abi, ownershipSigner);
const message = await forwarder.createMessage(
owner,
nonce,
nftContract,
tokenId,
tokenNonce
);
return ownershipSigner.signMessage(utils.arrayify(message));
}
async function durinCall({ callData, to, abi: _abi }, _opt, callback) {
const { from, nonce, nftContract, tokenId, tokenNonce } = decodeCalldata(callData);
// lookup current owner on mainnet
let owner: string;
try {
owner = await fetchCurrentOwner(
nftContract,
tokenId,
);
} catch (e) {
return callback(new rpc.Error.InternalError('Error fetching owner'));
}
// generate proof for owner or authorized
let proof: string;
try {
proof = await generateProof({
owner,
nonce,
nftContract,
tokenId,
to,
tokenNonce
// abi,
});
} catch (e) {
console.warn(e);
return callback(new rpc.Error.InternalError('Error generating proof'));
}
callback(null, proof);
}
server.expose('durin_call', durinCall);
server.listen(process.env.PORT);