코인 현물, 선물 투자를 위해 바이낸스에 가입했다면 이제 바이낸스 지갑으로 투자금을 송금해야 합니다. 보통 일단 국내 거래소인 업비트나 빗썸에서 코인을 매수한 후 해당 코인을 바이낸스 지갑으로 전송하는 방법으로 많이들 사용합니다.
Step 1. 업비트에서 테더(USDT) 매수
업비트에서 해도 되고 빗썸에서 해도 됩니다. 절차는 거의 동일합니다. 업비트나 빗썸 모두 보이스피싱 등의 금융사기 예방을 위해 원화를 입금한 후에는 24시간 동안은 디지털 자산 출금을 제한하고 있습니다. 이미 업비트나 빗썸에서 보유하고 있는 코인은 오늘 바로 바이낸스로 송금이 가능하지만 원화를 입금해서 송금하고자 하는 경우는 24시간 이후에 가능합니다.
업비트나 빗썸에서 바이낸스로 가상 자산을 송금할 때는 출금 수수료, 네트워크 수수료, 입금 수수료를 지불해야 하지만 현재 테더(USDT)로 송금할 경우 수수료가 무료입니다. 먼저 업비트에서 송금할 만큼의 테더를 매수합니다.
Step 2. 바이낸스 전자지갑 주소 확인
국내 거래소에 보유하고 있는 테더를 송금할 바이낸스의 지갑 주소를 확인해야 합니다. 바이낸스의 메인 화면 상단에 보면 [Add Funds] 버튼을 선택한 후 [On-Chain Deposit]을 선택합니다.
전송 받을 코인과 네트워크를 선택합니다. 우리는 테더(USDT)를 Tron 네트워크(TRX)를 통해 송금할 것이므로 아래 그림과 같이 선택합니다.
그러면 아래와 그림과 같이 전송 받을 지갑의 주소가 표시됩니다. 복사하기 버튼을 선택해서 복사해 둡니다.
Step 3. 업비트에서 테더(USDT) 송금하기
다른 거래소로 송금하는 것은 업비트 입장에서는 "출금"입니다. 하단 메뉴의 "입출금" 메뉴를 선택하고 보유한 테더를 선택합니다.
"출금" 버튼을 선택하면 출금 네트워크와 출금 수량을 입력해야 하는데, 네트워크를 잘못 입력할 경우 가상 자산이 유실될 수 있으므로 바이낸스에서 선택했던 네트워크와 동일한 Tron 네트워크(TRX)를 선택합니다. 출금 수량은 송금하길 원하는 테더를 입력하면 됩니다.
확인을 하게 되면 아래 그림과 같이 송금할 지갑의 주소에 아까 복사해 두었던 바이낸스의 지갑 주소를 붙여 넣은 후 완료하면 출금 요청이 완료됩니다.
Step 4. 바이낸스에서 입금 확인하기
출금 요청이 완료된 후 5분 정도 내에 송금한 가상 자산이 바이낸스에 도착합니다. 바이낸스 메인 화면으로 탭을 이동해 보면 가상 자산이 입금된 것을 확인할 수 있습니다.
자바스크립트는 원래 네스케이프가 브라우저 시장을 지배하고 있을 무렵 정적인 웹 페이지에 약간의 동적인 상호작용을 추가하기 위해 고안했던 프로그래밍 언어입니다. 초기에는 사용자의 동작에 반응하여 짧은 메시지를 표시한다던가 화면의 입력 값을 검증하기 위한 용도로 사용해왔었지만 이제는 독립적으로 하나의 애플리케이션을 구성할 수 있을만큼 눈부신 발전을 이루었습니다.
PYPL(PopularitY of Programming Language) 순위를 보아도 이제는 자바스크립트는 늘 상위권에 랭크되어 있는 인기 프로그래밍 언어입니다.
프로그래밍 언어 선호도 [출처: https://pypl.github.io]
이런 눈부신 발전으로 자바스크립트의 애플리케이션 규모는 점점 커지게 되었고, 기존의 방법으로는 코드의 관리와 유지보수가 쉽지 않은 과제가 되었습니다. 이런 성장에 따른 문제를 해결하기 위해 모듈 시스템이 등장했고, 모던 자바스크립트 라이브러리를 사용하여 개발하는 자바스크립트 프로젝트에서는 모듈 시스템이 필수적인 요소가 되었습니다.
모듈 시스템
자바스크립트에서는 크게 ES6 모듈과 CommonJS 모듈 시스템으로 나누어 사용합니다. 프론트엔드 애플리케이션을 구축할 때는 일반적으로 ECMAScript 2015에서 공식적으로 도입한 ES6 모듈 시스템을 사용합니다. React, Vue 등 점유율이 높은 라이브러리, 프레임워크를 지원하는 모듈들이 대부분 ES6 모듈을 지원하고 있습니다.
ES6 모듈 시스템은 아래 코드와 같이 import, export 문을 사용하여 모듈의 관계를 설정합니다.
util.js
export const sum = (a, b) => a + b;
export const multiple = (a, b) => a * b;
export const power = (a, b) => a ** b;
app.js
import { sum, multiple, power } from './util.js';
console.log(sum(2, 3)); //5
console.log(multiple(2, 3)); //6
console.log(power(2, 3)); //8
CommonJS 모듈은 전통적으로 사용하던 방식으로 require() 함수와 module.exports 구문을 사용하여 모듈 간의 관계를 정의합니다. 현재는 Node.js 에서 주로 사용하는 방식이지만 현재는 Node.js 의 전통적인 모듈들도 ES6 모듈을 지원하도록 변경되고 있는 추세입니다.
util.js
module.exports = {
sum: (a, b) => a + b,
multiple: (a, b) => a * b,
power: (a, b) => a ** b
};
app.js
var cal = require('./util.js');
console.log(cal.sum(2, 3)); //5
console.log(cal.multiple(2, 3)); //6
console.log(cal.power(2, 3)); //8
번들러(Bundler)의 탄생
위와 같은 자바스크립트 모듈 시스템을 먼저 활발하게 사용한 쪽은 Node.js 진영이었습니다. 하지만 Node.js로 작성한 모듈을 브라우저에서도 실행해보려고 하니 require() 함수로 정의한 의존성은 브라우저가 해석할 수 없었고, 브라우저에서 실행되도록 하려면 프로그램을 많이 변경해야 했습니다.
이런 필요로 해서 번들러의 초기 버전이 등장하는데 이름도 Browserify 입니다. 말 그대로 CommonJS 모듈 명세로 작성한 Node.js 기반의 애플리케이션도 브라우저에서 실행 가능하도록 하겠다는 컨셉이었습니다.
[출처: https://browserify.org]
Browserify 는 개발자가 모듈이나 파일을 require() 함수로 참조하면 그 의존성 트리를 크롤링하여 하나의 번들로 만들어서 브라우저에서도 Node.js 기반의 애플리케이션을 동작하게 해주었습니다. 그래서 번들러로써의 장점보다는 아래의 문구에 조금 더 힘을 주지 않았나 싶습니다.
Browserify lets you requires('modules') in the browser
이렇게 Browserify 가 수행한 작업이 번들링의 시초입니다.
웹팩 (Webpack)
모던 자바스크립트 프로젝트가 늘어나면서 Rollup, Vite, Parcel 등의 다양한 자바스크립트 번들러들이 출시되어 많은 장점을 어필하고 있지만 자바스크립트의 대표적인 번들러라고 하면 Webpack 을 꼽을 수 있습니다.
번들러의 개념 [출처: https://webpack.js.org]
Webpack 홈페이지에 있는 번들링에 대한 개념 설명입니다. 의존성을 가진 모듈들을 묶어서 하나의 정적 리소스로 변경해주는 작업을 한다는 것을 알 수 있습니다. 아래 내용 역시 Webpack 홈페이지 첫 화면에 나와 있는 내용으로 번들링의 기본 개념을 나타냅니다.
번들링의 개념 [출처: https://webpack.js.org]
번들링 확인
간단한 샘플 프로그램을 작성하여 Webpack으로 번들링을 되는 모습을 확인해 볼 수 있습니다. ES6 모듈 시스템을 사용하는 간단한 자바스크립트 프로젝트를 하나 만들어서 번들링을 하지 않은 채로 브라우저에서의 실행 결과를 확인해 보고, 번들링 후 실행하여 결과를 다시 확인해 보겠습니다.
먼저 아래 명령어로 프로젝트 루트로 사용할 경로를 생성한 후 package.json 파일을 생성합니다.
/project_root> mkdir bundleit
/project_root> cd bundleit
/project_root/bundleit> yarn init -y
생성한 경로를 VSCode로 열면 아래와 같은 모양입니다.
/js 경로를 하나 생성하고 util.js 파일을 아래와 같이 생성합니다.
export const sum = (a, b) => a + b;
export const multiple = (a, b) => a * b;
export const power = (a, b) => a ** b;
모두 작성하고 브라우저에서 index.html을 실행하면 아래와 같은 오류를 만날 수 있습니다.
브라우저가 해당 자바스크립트를 ES6 모듈로 인식하지 못해 발생하는 오류이므로 <script> 구문에 type=module 설정을 추가하여 사용할 수도 있습니다. 하지만 대부분의 경우 type=module 설정을 추가하기 보다는 번들링하여 사용합니다. 많은 경우 애플리케이션은 파일 몇 개로 이루어진 프로젝트가 아니라 수 많은 파일들로 관리하고 있기 때문입니다.
오류를 확인했으니 몇 줄 안되는 프로그램이긴 하지만 Webpack으로 번들링하여 동작을 확인해 보겠습니다. 아래 순서대로 진행해 보겠습니다.
어떤 장소의 위치를 나타내기 위해 우리는 구역을 나누고 해당 구역에 특정 이름을 붙이기로 약속을 했습니다. 이것을 우리는 "주소"라고 부릅니다. 어떤 장소를 찾아가기 위해서는 이렇게 약속한 주소를 보고 찾아갑니다. 찾아갈 때 버스를 타기도 하고, 걷기도 하고, 때로는 멀리 비행기를 타기도 하지만 결국은 이 주소를 기반으로 어딘가를 찾아갑니다.
아래는 관악구청 홈페이지에 안내되어 있는 도로명 주소를 명명하는 규칙에 대한 예시입니다.
[출처: 관악구청 홈페이지 (https://www.gwanak.go.kr)]
위와 같이 현재의 행정 구역에 따른 주소는 사회적 약속이지만 조금 더 효율적인 방안이 나오면 이런 약속은 다른 약속으로 대체할 수도 있습니다. 지번 주소를 사용하다가 도로명 주소를 추가한 것도 그 예로 볼 수 있습니다. 또 다른 예로는 2013년에 출시된 서비스로 지구를 3m x 3m로 나누고 각각의 구역에 세 개의 단어로 이루어진 키워드를 붙여 위치를 표시하는 "what3words"라는 서비스도 있습니다.
[출처: what3words (https://what3words.com)]
현재의 번지 위주의 주소 체계나 위도, 경도를 숫자로 표시하는 좌표 체계를 사람들이 조금 더 알기 쉽고, 공유하기 쉽도록 하기 위해 만들어진 서비스입니다.
이렇게 실제 존재하는 장소로 찾아가기도 하지만 우리는 인터넷이라는 가상 공간에서도 네이버, 구글, 인스타그램 등등의 어딘가를 찾아갑니다. 이런 서비스들도 모두 고유의 주소를 가지고 있는데 이 주소는 IP 주소라고 불리우는 숫자로만 이루어진 주소여서 기억하고 공유하기가 쉽지 않습니다.
DNS의 등장
하여 이 어려운 숫자로 이루어진 주소를 조금 더 기억하고 공유하기 쉬운 주소 체계로 변경해보기 위해 도입한 개념이 도메인(Domain)이고 이 도메인을 관리하는 시스템을 DNS(Domain Name System)라고 합니다.
DNS는 Jon Postel과 Paul Mockapetris라는 사람이 구상했는데 DNS가 나오기 전까지는 SRI(Standford Research Institute)에서 전 세계의 hosts 파일을 수작업으로 관리했습니다. SRI의 hosts 파일을 다운로드하여 해당 호스트 이름으로 접속해야 했으므로 사용자는 해당 파일을 늘 최신 버전으로 다운로드 할 필요가 있었습니다.
DNS가 생긴 이후에는 전 세계의 IP 주소와 도메인을 관리하는 역할을 DNS 서버에서 담당합니다.
PC에서 인터넷의 특정 사이트에 접속하기 위해 웹 브라우저에 도메인 주소를 입력하면 먼저 로컬 PC의 hosts 파일을 먼저 찾아본 후 해당 도메인 정보가 등록된 내용이 없다면 DNS 서버에 접속하여 도메인에 대한 IP 주소를 찾습니다. 일반적으로 가정에서 사용하는 DNS는 ISP(Internet Service Provider: LG U+, SK 브로드밴드 등)에서 자동으로 세팅하는 정보를 사용하지만 이슈가 있을 경우에는 Public DNS를 사용할 수도 있습니다.
현재 사용하고 있는 DNS를 조회하기 위해서는 Command prompt에 ipconfig/all 명령어를 입력하면 아래와 같이 조회할 수 있습니다.
DNS 서버로 표시되는 주 서버/보조 서버인 168.124.101.2, 203.248.252.2를 nslookup 명령어로 찾아보면 DNS 서버를 확인할 수 있습니다.
도메인 이름 구조
위 내용처럼 DNS 서버는 IP 주소와 도메인 이름을 짝지어 관리하는 기능이 있으며 클라이언트가 도메인 이름으로 질의(DNS Query)하면 해당 도메인에 연결되어 있는 IP 주소를 응답해 주는 역할을 합니다.
검색 엔진인 구글의 모바일일 주소인 m.google.com 도메인의 구조를 보면 아래와 같습니다.
도메인에서 가장 오른쪽의 dot(.)은 원래는 있어야 하지만 생략되어 있는 것이며 Root name server를 의미합니다. 사용자가 도메인을 입력하여 검색하면 Root name server에서부터 검색을 시작하며, 아래와 같이 역순으로 검색하여 서버의 주소를 획득합니다.
Root name server에서는 .com을 담당하는 TLD(Top-Level Domain)의 주소를 알려줍니다.
TLD에서는 google.com을 담당하는 SLD(Second-Level Domain)의 주소를 알려줍니다.
SLD에서는 m.google.com을 담당하는 sub DNS server에 질의하여 해당 도메인에 대한 IP 주소를 획득합니다.
아래 한국인터넷정보센터의 자료에 도메인의 구조가 잘 정리되어 있습니다.
[출처: 한국인터넷정보센터]
DNS 등록 방법
DNS 등록은 보통 가비아나 후이즈 등의 관리 대행 업체를 통해 등록하고 해당 업체의 Name server를 사용합니다. 등록하는 절차는 IP를 찾는 순서와 반대로 진행합니다.
등록자가 보유하고 있는 도메인을 DNS에 등록할 때 등록대행자에게 해당 도메인의 name server 주소를 전달합니다.
등록대행자는 이 정보를 등록소에 전달합니다.
등록소는 이 정보를 자신이 관리하는 TLD에 기록합니다.
ICANN(Internet Corporation for Assigned Names and Numbers - 국제 인터넷 주소 관리기구)에서 관리하는 Root name server 의 가장 중요한 역할은 전 세계에 있는 TLD의 주소를 기억하는 것입니다. 위의 과정을 통해 IP와 도메인을 등록해 두면 사용자가 브라우저에 도메인을 입력했을 때, 등록의 역순인 Root name server - TLD - SLD를 거쳐 해당 도메인의 IP를 획득할 수 있습니다.
NSLOOKUP
nslookup은 DNS 정보를 조회하는 도구입니다. IP에 대한 도메인을 알고 싶거나, 반대로 도메인에 대한 IP 정보를 알고 싶을 때 아래와 같이 입력하여 확인할 수 있습니다.
코니는 영어 단어가 적힌 카드 뭉치 두 개를 선물로 받았습니다. 코니는 다음과 같은 규칙으로 카드에 적힌 단어들을 사용해 원하는 순서의 단어 배열을 만들 수 있는지 알고 싶습니다.
원하는 카드 뭉치에서 카드를 순서대로 한 장씩 사용합니다.
한 번 사용한 카드는 다시 사용할 수 없습니다.
카드를 사용하지 않고 다음 카드로 넘어갈 수 없습니다.
기존에 주어진 카드 뭉치의 단어 순서는 바꿀 수 없습니다.
예를 들어 첫 번째 카드 뭉치에 순서대로 ["i", "drink", "water"], 두 번째 카드 뭉치에 순서대로 ["want", "to"]가 적혀있을 때 ["i", "want", "to", "drink", "water"] 순서의 단어 배열을 만들려고 한다면 첫 번째 카드 뭉치에서 "i"를 사용한 후 두 번째 카드 뭉치에서 "want"와 "to"를 사용하고 첫 번째 카드뭉치에 "drink"와 "water"를 차례대로 사용하면 원하는 순서의 단어 배열을 만들 수 있습니다.
문자열로 이루어진 배열 cards1, cards2와 원하는 단어 배열 goal이 매개변수로 주어질 때, cards1과 cards2에 적힌 단어들로 goal를 만들 있다면 "Yes"를, 만들 수 없다면 "No"를 return하는 solution 함수를 완성해주세요.
입출력 예
cards1
cards2
goal
result
["i", "drink", "water"]
["want", "to"]
["i", "want", "to", "drink", "water"]
"Yes"
["i", "water", "drink"]
["want", "to"]
["i", "want", "to", "drink", "water"]
"No"
풀이
만들고자 하는 카드의 배열은 goal 입니다. goal 을 만들기 위해 cards1 과 cards2 배열 중 가장 첫 번째 요소를 꺼내어 goal 을 만들 수 있으면 "Yes", 만들 수 없다면 "No" 를 응답하면 됩니다.
만들고자하는 결과인 goal 요소를 순회하면서 cards1 과 cards2 중 첫 번째 요소에 해당 단어가 있는지 살펴보고, 해당 단어가 있을 경우에 사용한 카드(요소)는 버리도록 shift() 메소드를 사용해서 배열의 첫 번째 요소를 삭제하겠습니다.
function solution(cards1, cards2, goal) {
for (let ele of goal) {
if (ele === cards1[0]) {
cards1.shift();
} else if (ele === cards2[0]) {
cards2.shift();
} else {
return 'No';
}
}
return 'Yes';
}
for ~ of 구문으로 배열을 순회하면서 해당 카드(요소)가 cards1 과 cards2 중 하나라도 첫 번째 요소에 있는지 확인하고 있을 경우에는 확인한 카드(요소)를 shift() 메소드로 뽑아서 버리고 다음 카드(요소)를 순회합니다. 그리고 없을 경우에는 해당 단어를 만들 수 없으므로 바로 "No"를 응답합니다.
정수 n과 문자열 control이 주어집니다. control은 "w", "a", "s", "d"의 4개의 문자로 이루어져 있으며, control의 앞에서부터 순서대로 문자에 따라 n의 값을 바꿉니다.
"w": n이 1 커집니다.
"s": n이 1 작아집니다.
"d": n이 10 커집니다.
"a": n이 10 작아집니다.
위 규칙에 따라 n을 바꿨을 때 가장 마지막에 나오는 n의 값을 return 하는 solution 함수를 완성해 주세요.
입출력 예
n
control
result
0
"wsdawsdassw"
-1
풀이
수가 n부터 시작하므로 모든 control 요소의 값을 더한 후 n에 더해주면 되는 문제입니다. for 문과 if 문을 사용해서 작성해보면 아래처럼 작성할 수 있습니다.
function solution(n, control) {
for (let inx=0; inx<control.length; inx++) {
if (control[inx] === 'w') {
n = n + 1;
} else if (control[inx] === 's') {
n = n - 1;
} else if (control[inx] === 'd') {
n = n + 10;
} else {
n = n - 10;
}
}
return n;
}
위 내용은 누적값을 구하는 내용이므로 reduce 함수를 사용해서 아래와 같이 작성해 볼 수도 있습니다.
function solution(n, control) {
const point = {'w': 1, 's': -1, 'd': 10, 'a': -10}
return [...control].reduce((a, v) => a + point[v], n);
}
먼저 각 문자 당 수에 쉽게 접근하기 위해 문자와 수를 연결한 오브젝트를 하나 생성합니다.
정수가 담긴 리스트 num_list가 주어집니다. num_list의 홀수만 순서대로 이어 붙인 수와 짝수만 순서대로 이어 붙인 수의 합을 return하도록 solution 함수를 완성해주세요.
입출력 예
num_list
result
[3, 4, 5, 2, 1]
393
[5, 7, 8, 3]
581
풀이
간단하게 주어진 배열을 반복하면서 홀수와 짝수를 구한 후 이어 붙여서 두 수의 합을 구하면 됩니다. 가장 간단하게 for 문을 사용해서 아래와 같이 풀어볼 수 있습니다.
function solution(num_list) {
let odd = '';
let even = '';
for (let inx=0; inx<num_list.length; inx++) {
if (num_list[inx] % 2 === 0) {
even += num_list[inx];
} else {
odd += num_list[inx];
}
}
return Number(odd) + Number(even);
}
홀수와 짝수는 값을 2로 나눈 나머지가 0이면 짝수, 아니면 홀수로 판단하면 됩니다. 해당 조건으로 판단하여 홀수와 짝수의 문자열을 만들고 그 합을 구해 return 하는 문제입니다.
위 문제를 filter 메소드를 사용해서 풀어보면 아래와 같습니다.
function solution(num_list) {
const odd = num_list.filter(v => v % 2).join('');
const even = num_list.filter(v => !(v % 2)).join('');
return Number(odd) + Number(even);
}
개념은 같습니다. filter 메소드는 파라미터로 전달하는 콜백 함수의 결과가 참인 경우로 새 배열을 만들어서 return 해줍니다. 하여 홀수는 v로 나눈 나머지가 1(true)인 수들을 모아서 새 배열을 생성한 후 join으로 하나의 문자열로 변환합니다. 짝수도 마찬가지 방법으로 구할 수 있습니다.