@@ -18705,27 +18705,44 @@ function bytes32ify(value) {
1870518705function base58Encode(data) {
1870618706 return Base58.encode(concat([data, hexDataSlice(sha256$1(sha256$1(data)), 0, 4)]));
1870718707}
18708+ const matchers = [
18709+ new RegExp("^(https):/\/(.*)$", "i"),
18710+ new RegExp("^(data):(.*)$", "i"),
18711+ new RegExp("^(ipfs):/\/(.*)$", "i"),
18712+ new RegExp("^eip155:[0-9]+/(erc[0-9]+):(.*)$", "i"),
18713+ ];
18714+ function _parseString(result) {
18715+ try {
18716+ return toUtf8String(_parseBytes(result));
18717+ }
18718+ catch (error) { }
18719+ return null;
18720+ }
18721+ function _parseBytes(result) {
18722+ if (result === "0x") {
18723+ return null;
18724+ }
18725+ const offset = BigNumber.from(hexDataSlice(result, 0, 32)).toNumber();
18726+ const length = BigNumber.from(hexDataSlice(result, offset, offset + 32)).toNumber();
18727+ return hexDataSlice(result, offset + 32, offset + 32 + length);
18728+ }
1870818729class Resolver {
18709- constructor(provider, address, name) {
18730+ // The resolvedAddress is only for creating a ReverseLookup resolver
18731+ constructor(provider, address, name, resolvedAddress) {
1871018732 defineReadOnly(this, "provider", provider);
1871118733 defineReadOnly(this, "name", name);
1871218734 defineReadOnly(this, "address", provider.formatter.address(address));
18735+ defineReadOnly(this, "_resolvedAddress", resolvedAddress);
1871318736 }
1871418737 _fetchBytes(selector, parameters) {
1871518738 return __awaiter$9(this, void 0, void 0, function* () {
18716- // keccak256("addr(bytes32,uint256)")
18717- const transaction = {
18739+ // e.g. keccak256("addr(bytes32,uint256)")
18740+ const tx = {
1871818741 to: this.address,
1871918742 data: hexConcat([selector, namehash(this.name), (parameters || "0x")])
1872018743 };
1872118744 try {
18722- const result = yield this.provider.call(transaction);
18723- if (result === "0x") {
18724- return null;
18725- }
18726- const offset = BigNumber.from(hexDataSlice(result, 0, 32)).toNumber();
18727- const length = BigNumber.from(hexDataSlice(result, offset, offset + 32)).toNumber();
18728- return hexDataSlice(result, offset + 32, offset + 32 + length);
18745+ return _parseBytes(yield this.provider.call(tx));
1872918746 }
1873018747 catch (error) {
1873118748 if (error.code === Logger.errors.CALL_EXCEPTION) {
@@ -18832,6 +18849,94 @@ class Resolver {
1883218849 return address;
1883318850 });
1883418851 }
18852+ getAvatar() {
18853+ return __awaiter$9(this, void 0, void 0, function* () {
18854+ const linkage = [];
18855+ try {
18856+ const avatar = yield this.getText("avatar");
18857+ if (avatar == null) {
18858+ return null;
18859+ }
18860+ for (let i = 0; i < matchers.length; i++) {
18861+ const match = avatar.match(matchers[i]);
18862+ if (match == null) {
18863+ continue;
18864+ }
18865+ switch (match[1]) {
18866+ case "https":
18867+ linkage.push({ type: "url", content: avatar });
18868+ return { linkage, url: avatar };
18869+ case "data":
18870+ linkage.push({ type: "data", content: avatar });
18871+ return { linkage, url: avatar };
18872+ case "ipfs":
18873+ linkage.push({ type: "ipfs", content: avatar });
18874+ return { linkage, url: `https:/\/gateway.ipfs.io/ipfs/${avatar.substring(7)}` };
18875+ case "erc721":
18876+ case "erc1155": {
18877+ // Depending on the ERC type, use tokenURI(uint256) or url(uint256)
18878+ const selector = (match[1] === "erc721") ? "0xc87b56dd" : "0x0e89341c";
18879+ linkage.push({ type: match[1], content: avatar });
18880+ // The owner of this name
18881+ const owner = (this._resolvedAddress || (yield this.getAddress()));
18882+ const comps = (match[2] || "").split("/");
18883+ if (comps.length !== 2) {
18884+ return null;
18885+ }
18886+ const addr = yield this.provider.formatter.address(comps[0]);
18887+ const tokenId = hexZeroPad(BigNumber.from(comps[1]).toHexString(), 32);
18888+ // Check that this account owns the token
18889+ if (match[1] === "erc721") {
18890+ // ownerOf(uint256 tokenId)
18891+ const tokenOwner = this.provider.formatter.callAddress(yield this.provider.call({
18892+ to: addr, data: hexConcat(["0x6352211e", tokenId])
18893+ }));
18894+ if (owner !== tokenOwner) {
18895+ return null;
18896+ }
18897+ linkage.push({ type: "owner", content: tokenOwner });
18898+ }
18899+ else if (match[1] === "erc1155") {
18900+ // balanceOf(address owner, uint256 tokenId)
18901+ const balance = BigNumber.from(yield this.provider.call({
18902+ to: addr, data: hexConcat(["0x00fdd58e", hexZeroPad(owner, 32), tokenId])
18903+ }));
18904+ if (balance.isZero()) {
18905+ return null;
18906+ }
18907+ linkage.push({ type: "balance", content: balance.toString() });
18908+ }
18909+ // Call the token contract for the metadata URL
18910+ const tx = {
18911+ to: this.provider.formatter.address(comps[0]),
18912+ data: hexConcat([selector, tokenId])
18913+ };
18914+ let metadataUrl = _parseString(yield this.provider.call(tx));
18915+ if (metadataUrl == null) {
18916+ return null;
18917+ }
18918+ linkage.push({ type: "metadata-url", content: metadataUrl });
18919+ // ERC-1155 allows a generic {id} in the URL
18920+ if (match[1] === "erc1155") {
18921+ metadataUrl = metadataUrl.replace("{id}", tokenId.substring(2));
18922+ }
18923+ // Get the token metadata
18924+ const metadata = yield fetchJson(metadataUrl);
18925+ // Pull the image URL out
18926+ if (!metadata || typeof (metadata.image) !== "string" || !metadata.image.match(/^https:\/\//i)) {
18927+ return null;
18928+ }
18929+ linkage.push({ type: "metadata", content: JSON.stringify(metadata) });
18930+ linkage.push({ type: "url", content: metadata.image });
18931+ return { linkage, url: metadata.image };
18932+ }
18933+ }
18934+ }
18935+ }
18936+ catch (error) { }
18937+ return null;
18938+ });
18939+ }
1883518940 getContentHash() {
1883618941 return __awaiter$9(this, void 0, void 0, function* () {
1883718942 // keccak256("contenthash()")
@@ -19994,6 +20099,30 @@ class BaseProvider extends Provider {
1999420099 return name;
1999520100 });
1999620101 }
20102+ getAvatar(nameOrAddress) {
20103+ return __awaiter$9(this, void 0, void 0, function* () {
20104+ let resolver = null;
20105+ if (isHexString(nameOrAddress)) {
20106+ // Address; reverse lookup
20107+ const address = this.formatter.address(nameOrAddress);
20108+ const reverseName = address.substring(2).toLowerCase() + ".addr.reverse";
20109+ const resolverAddress = yield this._getResolver(reverseName);
20110+ if (!resolverAddress) {
20111+ return null;
20112+ }
20113+ resolver = new Resolver(this, resolverAddress, "_", address);
20114+ }
20115+ else {
20116+ // ENS name; forward lookup
20117+ resolver = yield this.getResolver(nameOrAddress);
20118+ }
20119+ const avatar = yield resolver.getAvatar();
20120+ if (avatar == null) {
20121+ return null;
20122+ }
20123+ return avatar.url;
20124+ });
20125+ }
1999720126 perform(method, params) {
1999820127 return logger$t.throwError(method + " not implemented", Logger.errors.NOT_IMPLEMENTED, { operation: method });
1999920128 }
0 commit comments